home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 20 / Cream of the Crop 20 (Terry Blount) (1996).iso / program / freeli20.zip / freelib1.asx < prev    next >
Text File  |  1996-07-01  |  99KB  |  3,322 lines

  1. ~~~C_START
  2. Ideal
  3.  
  4. Extrn       main:near
  5. Public      startup, exit
  6. Public      TopByte, AtExitCnt
  7.  
  8. Model Tiny
  9. CodeSeg
  10. P186
  11.  
  12. ;****************** startup() -- Start program
  13.  
  14. Proc        startup
  15.  
  16.             mov cx,0121h            ;Check for 186+
  17.             shl ch,cl
  18.             jz p0_badcpu
  19.  
  20.             mov ax,3001h            ;Check for DOS 4.0
  21.             int 21h
  22.             cmp al,4
  23.             jb p0_baddos
  24.  
  25.             mov ah,4Ah              ;Modify memory allocation
  26.             mov bx,1000h            ;Keep first 64K
  27.             int 21h                 ;DOS call
  28.  
  29.             mov sp,0FF00h           ;Shift stack down 256 bytes
  30.  
  31.             mov ax,2523h            ;Set null Ctrl-C handler
  32.             mov dx,offset IntRet    ;so that Ctrl-C can't
  33.             int 21h                 ;abort the program
  34.  
  35.             mov ax,3500h            ;Get current Int 0 handler
  36.             int 21h                 ; (divide by zero)
  37.  
  38.             mov [word OldInt0],bx   ;Save handler
  39.             mov [word OldInt0+2],es
  40.  
  41.             push cs                 ;Restore ES
  42.             pop es
  43.  
  44.             mov ax,2500h            ;Set the divide by zero
  45.             mov dx,offset DivZero   ;handler: now it just
  46.             int 21h                 ;ignores the error
  47.  
  48.             mov ax,0FB00h           ;Initialize dynamic memory
  49.             sub ax,offset TopByte   ;leaving 768 bytes for the
  50.             mov [word TopByte],ax   ;stack (which is at 0FF00h)
  51.             mov [byte TopByte+2],2  ;Initial block is free, last
  52.  
  53.             mov di,sp               ;Parse arguments
  54.             call ParseArgs
  55.  
  56.             call main               ;Call main function
  57.  
  58.             push ax                 ;Terminate with return code
  59.             call exit
  60.  
  61. p0_baddos:  push offset BadDosStr   ;'Bad Dos' message
  62.             jmp p0_error
  63.  
  64. p0_badcpu:  push offset BadCPUStr   ;'Bad CPU' message
  65.  
  66. p0_error:   mov dx,offset BadStr    ;Print first part
  67.             mov ah,9
  68.             int 21h
  69.             pop dx                  ;Print second part
  70.             int 21h
  71.             mov ax,4CFFh            ;Return with error 255
  72.             int 21h
  73.  
  74. EndP        startup
  75.  
  76. ;****************** DivZero -- Divide by zero handler
  77.  
  78. Proc        DivZero
  79.  
  80.             push bp                 ;Set up stack frame
  81.             mov bp,sp
  82.             pusha                   ;Save all registers
  83.             push ds
  84.  
  85.             xor cx,cx               ;CX = displacement
  86.  
  87.             mov ds,[bp+4]           ;DS:BX = DIV instruction
  88.             mov bx,[bp+2]
  89.             mov al,[bx+1]           ;AL = AH = ModRM byte
  90.             mov ah,al
  91.  
  92.             and al,0C0h             ;Mask off mode bits
  93.             cmp al,0C0h             ;Mode = 11 (no disp)?
  94.             je DZ_dis0
  95.             cmp al,040h             ;Mode = 01 (1 byte disp)?
  96.             je DZ_dis1
  97.             cmp al,080h             ;Mode = 10 (2 byte disp)?
  98.             je DZ_dis2
  99.             cmp ah,036h             ;Mode = 00.  No disp except
  100.             jne DZ_dis0             ;if R/M = 110 (2 byte disp).
  101.  
  102. DZ_dis2:    inc cx                  ;2 byte displacement
  103. DZ_dis1:    inc cx                  ;1 byte displacement
  104. DZ_dis0:    inc cx                  ;Instruction is two bytes
  105.             inc cx
  106.             add [bp+2],cx           ;Skip past instruction
  107.  
  108. DZ_done:    pop ds                  ;Restore registers
  109.             popa
  110.             pop bp                  ;Delete stack frame
  111. IntRet:     iret                    ;Interrupt return
  112.  
  113. EndP        DivZero
  114.  
  115. ;****************** Internal data
  116.  
  117. OldInt0:                            ;Old divide-by-zero handler
  118. BadStr      db 'Need at least $'    ;OK to overwrite strings
  119. BadCPUStr   db 'an 80186 CPU',13,10,'$'
  120. BadDosStr   db 'DOS 4.0',13,10,'$'
  121.  
  122. AtExitCnt   dw 0                    ;Exit function count
  123. AtExitTblO  equ 0FF60h              ;Exit function table offset
  124.  
  125. ;****************** exit() -- Terminate program
  126. ;void exit(int retval);
  127.  
  128. Proc        exit
  129.  
  130.             mov ax,2500h            ;Reset the default divide
  131.             mov dx,[word OldInt0]   ;by zero handler
  132.             mov ds,[word OldInt0+2]
  133.             int 21h
  134.  
  135.             push cs                 ;Restore DS
  136.             pop ds
  137.  
  138.             mov cx,[AtExitCnt]      ;CX = atexit count
  139.             jcxz p1_done            ;No exit functions?
  140.             mov si,AtExitTblO       ;SI = atexit table
  141.  
  142. p1_loop:    lodsw                   ;Get function
  143.             call ax                 ;Call function
  144.             loop p1_loop            ;Loop back
  145.  
  146. p1_done:    pop ax ax               ;Pop arg into AX
  147.             mov ah,4Ch              ;Terminate program
  148.             int 21h                 ;DOS call
  149.  
  150. EndP        exit
  151.  
  152. ;**************************** ParseArgs() -- internal: Parse arguments
  153.  
  154. Proc        ParseArgs
  155.             ;Supply DI = 256-byte buffer, CS = DS = ES
  156.             ;Returns CX = number of arguments
  157.             ;the buffer will contain a list of
  158.             ;near offsets to AsciiZ strings
  159.             ;(and the strings themselves)
  160.  
  161.             push es                 ;Save registers
  162.             pusha
  163.  
  164.             mov bx,di               ;BX = buffer
  165.             mov cl,[80h]            ;CX = length of command line
  166.             xor ch,ch               ;which is stored at 80h
  167.  
  168.             push cx                 ;Save CX
  169.             mov si,81h              ;SI = command line
  170.             add di,80h              ;DI = second half of buffer
  171.             push di                 ;Save DI
  172.             rep movsb               ;Move command line out of DTA
  173.             xor al,al               ;Replace the CR at the end
  174.             stosb                   ;with a null
  175.             pop di cx               ;Restore DI, length in CX
  176.             inc cx                  ;Make length include last null
  177.             xor dx,dx               ;Zero argument counter
  178.             mov al,' '              ;AL = space
  179.  
  180. p2_loop:    repe scasb              ;Search for a non-space
  181.             dec di
  182.             inc cx
  183.             cmp [byte di],0         ;Is it a null?
  184.             je p2_done
  185.             mov [bx],di             ;Store offset in list
  186.             inc bx                  ;Advance pointers
  187.             inc bx
  188.             inc dx
  189.             repne scasb             ;Search for a space
  190.             mov [byte di-1],0       ;Replace it by a null
  191.             jmp p2_loop             ;Loop back
  192.  
  193. p2_done:    mov es,dx               ;Tricky -- put count in ES
  194.             popa                    ;Restore general registers
  195.             mov cx,es               ;Count in CX
  196.             pop es                  ;Restore ES
  197.             ret                     ;Return
  198.  
  199. EndP        ParseArgs
  200.  
  201. UDataSeg                            ;Uninit. data seg: dummy
  202.  
  203. Label       TopByte                 ;Top byte of code (start of heap)
  204.  
  205. End
  206.  
  207. ~~~C_ATEXIT
  208. Ideal
  209.  
  210. Extrn       AtExitCnt:word
  211. Public      atexit
  212.  
  213. Model Tiny
  214. CodeSeg
  215. P186
  216.  
  217. AtExitTblO  equ 0FF60h              ;Exit function table offset
  218.  
  219. ;****************** atexit() -- Add exit function
  220. ;int atexit(void *func);
  221.  
  222. func        equ bp+4
  223.  
  224. Proc        atexit
  225.  
  226.             push bp                 ;Set up stack frame
  227.             mov bp,sp
  228.             push bx                 ;Save BX
  229.  
  230.             cmp [word AtExitCnt],16 ;16 functions max
  231.             jae p1_error
  232.  
  233.             mov bx,[AtExitCnt]      ;BX = offset
  234.             add bx,bx
  235.             mov ax,[func]           ;AX = function
  236.             mov [AtExitTblO+bx],ax  ;Add function to table
  237.             inc [word AtExitCnt]    ;Increment count
  238.  
  239. p1_done:    pop bx                  ;Restore BX
  240.             pop bp                  ;Delete stack frame
  241.             ret 2                   ;Return
  242.  
  243. p1_error:   xor ax,ax               ;Return 0: failure
  244.             jmp p1_done
  245.  
  246. EndP        atexit
  247.  
  248. End
  249.  
  250. ~~~C_PUTCHR
  251. Ideal
  252.  
  253. Public      PUT_CHAR
  254.  
  255. Model Tiny
  256. CodeSeg
  257. P186
  258.  
  259. ;****************** PUT_CHAR -- Like Int 29h but with redirection.
  260. ;                               Takes AL = char.
  261.  
  262. Proc        PUT_CHAR
  263.  
  264.             pusha                   ;Save registers
  265.             xchg dx,ax              ;STDOUT output, DL = char
  266.             mov ah,2
  267.             int 21h                 ;DOS call
  268.             popa                    ;Restore registers
  269.             ret                     ;Return
  270.  
  271. EndP        PUT_CHAR
  272.  
  273. End
  274.  
  275. ~~~C_FILES
  276. Ideal
  277.  
  278. Public      fopen,fclose,fsetbuf
  279.  
  280. Model Tiny
  281. CodeSeg
  282. P186
  283.  
  284. ;****************** File Structure . . .
  285.  
  286. ;                   Offset  Size    Description
  287.  
  288. ;                     0     Word    File handle
  289. ;                     2     Byte    File mode
  290. ;                     3     Byte    Modify flag
  291. ;                     4     Dword   Buffer position in file
  292. ;                     8     Word    Buffer pointer position
  293. ;                     10    Word    Number of bytes in buffer
  294. ;                     12    Word    Size of buffer (N)
  295. ;                     14    Word    Signature 'FI'
  296. ;                     16    N bytes File buffer
  297.  
  298. BUF_SIZ     dw 1024                 ;Buffer size (default 1K)
  299.  
  300. F_MODES     db 00h,01h              ;0 = open for read
  301.             db 02h,11h              ;1 = open/create for read/write
  302.             db 02h,01h              ;2 = open for read/write
  303.             db 02h,12h              ;3 = create/truncate for read/write
  304.             db 02h,10h              ;4 = create for read/write
  305.             db 6 dup(0)             ;Fail for 5, 6, 7
  306.  
  307. ;****************** fopen() -- Open a buffered file
  308. ;int fopen(char *fname, int mode);
  309.  
  310. fname       = bp+6
  311. mode        = bp+4
  312.  
  313. Proc        fopen
  314.  
  315.             push bp                 ;Set up stack frame
  316.             mov bp,sp
  317.             push ds                 ;Save registers
  318.             pusha
  319.  
  320.             mov bx,[mode]           ;BX = mode
  321.             and bx,7                ;Mode mod 8
  322.             add bx,bx
  323.             mov dl,[F_MODES+bx+1]   ;BX:DX = DOS mode
  324.             mov bl,[F_MODES+bx]
  325.             xor dh,dh
  326.             xor bh,bh
  327.  
  328.             mov ax,6C00h            ;Extended open file
  329.             xor cx,cx               ;Normal attribute
  330.             mov si,[fname]          ;SI = name
  331.             int 21h                 ;DOS call
  332.             jc p1_err1              ;Check for errors
  333.  
  334.             xchg dx,ax              ;DX = handle
  335.  
  336.             mov ah,48h              ;Allocate memory
  337.             mov bx,[BUF_SIZ]        ;BX = num. of paras
  338.             shr bx,4                ; = (BUF_SIZ / 16) + 1
  339.             inc bx
  340.             int 21h                 ;DOS call
  341.             jc p1_err2              ;Check for errors
  342.  
  343.             mov ds,ax               ;DS = segment
  344.             mov [word 0],dx         ;[word 0] = handle
  345.             mov cx,[mode]
  346.             mov [word 2],cx         ;[word 2] = mode
  347.             xor bx,bx
  348.             mov [word 4],bx         ;[dword 4] = buffer position
  349.             mov [word 6],bx
  350.             mov [word 8],bx         ;[word 8] = buffer pointer
  351.             mov bx,[cs:BUF_SIZ]
  352.             mov [word 12],bx        ;[word 12] = buffer size
  353.             mov [word 14],'FI'      ;[word 14] = 'FI': signature
  354.  
  355.             mov bx,dx               ;BX = handle
  356.             mov ah,3Fh              ;Read file
  357.             mov cx,[cs:BUF_SIZ]     ;BUF_SIZ bytes
  358.             mov dx,16               ;Buffer offset
  359.             int 21h                 ;DOS call
  360.  
  361.             mov [word 10],ax        ;Set byte count
  362.  
  363. p1_done:    popa                    ;Restore registers
  364.             mov ax,ds               ;Result in AX
  365.             pop ds
  366.             pop bp                  ;Delete stack frame
  367.             ret 4                   ;Return
  368.  
  369. p1_err2:    mov ah,3Eh              ;Out of memory, close file
  370.             mov bx,dx               ;BX = handle
  371.             int 21h                 ;DOS call
  372.  
  373. p1_err1:    push 0                  ;Error, return 0
  374.             pop ds
  375.             jmp p1_done
  376.  
  377. EndP        fopen
  378.  
  379. ;****************** fclose() -- Close a buffered file
  380. ;void fclose(int fptr);
  381.  
  382. fptr        = bp+4
  383.  
  384. Proc        fclose
  385.  
  386.             push bp                 ;Set up stack frame
  387.             mov bp,sp
  388.             push ds es              ;Save registers
  389.             pusha
  390.  
  391.             mov ds,[fptr]           ;DS = seg of file
  392.             cmp [word 14],'FI'      ;Check for signature
  393.             jne p2_done
  394.  
  395.             mov bx,[word 0]         ;BX = handle
  396.  
  397.             cmp [byte 2],0          ;Read only, can't write buffer
  398.             je p2_skip
  399.  
  400.             mov ax,4200h            ;Move file ptr
  401.             mov cx,[word 6]         ;CX:DX = buffer pos
  402.             mov dx,[word 4]
  403.             int 21h                 ;DOS call
  404.  
  405.             mov ah,40h              ;Write file
  406.             mov cx,[word 10]        ;CX = bytes
  407.             mov dx,16               ;Buffer offset
  408.             int 21h                 ;DOS call
  409.  
  410. p2_skip:    mov ah,3Eh              ;Close file
  411.             int 21h                 ;DOS call
  412.  
  413.             mov ah,49h              ;Free memory
  414.             push ds                 ;ES = segment
  415.             pop es
  416.             int 21h                 ;DOS call
  417.  
  418. p2_done:    popa                    ;Restore registers
  419.             pop es ds
  420.             pop bp                  ;Delete stack frame
  421.             ret 2                   ;Return
  422.  
  423. EndP        fclose
  424.  
  425. ;****************** fsetbuf() -- Set buffer size (for future use)
  426. ;int fsetbuf(int bsize);
  427.  
  428. bsize       = bp+4
  429.  
  430. Proc        fsetbuf
  431.  
  432.             push bp                 ;Set up stack frame
  433.             mov bp,sp
  434.  
  435.             mov ax,[bsize]          ;AX = size
  436.             and ax,7FF0h            ;Put it in range
  437.             cmp ax,128
  438.             jb $+5
  439.             mov ax,128
  440.             mov [BUF_SIZ],ax        ;Set buffer size
  441.  
  442.             pop bp                  ;Delete stack frame
  443.             ret 2                   ;Return
  444.  
  445. EndP        fsetbuf
  446.  
  447. End
  448.  
  449. ~~~C_FPUTC
  450. Ideal
  451.  
  452. Public      fputc
  453.  
  454. Model Tiny
  455. CodeSeg
  456. P186
  457.  
  458. ;****************** fputc() -- Put char to buffered file
  459. ;int fputc(int fptr, int chr);
  460.  
  461. fptr        = bp+6
  462. chr         = bp+4
  463.  
  464. Proc        fputc
  465.  
  466.             push bp                 ;Set up stack frame
  467.             mov bp,sp
  468.             push ds si bx cx dx     ;Save registers
  469.  
  470.             mov ds,[fptr]           ;DS = seg of file
  471.             cmp [word 14],'FI'      ;Check for signature
  472.             jne p1_error
  473.  
  474.             mov bx,[word 0]         ;BX = handle
  475.  
  476.             cmp [byte 2],0          ;Read only, can't put char
  477.             je p1_error
  478.  
  479.             mov si,[word 8]         ;SI = pointer pos
  480.             cmp si,[word 12]        ;Filled buffer?
  481.             jb p1_write             ;Jump if not
  482.  
  483.             mov ax,4200h            ;Move file ptr
  484.             mov cx,[word 6]         ;CX:DX = buffer pos
  485.             mov dx,[word 4]
  486.             int 21h                 ;DOS call
  487.  
  488.             mov ah,40h              ;Write file
  489.             mov cx,[word 12]        ;CX = bytes
  490.             mov dx,16               ;Buffer offset
  491.             int 21h                 ;DOS call
  492.  
  493.             mov ah,3Fh              ;Read file, same size
  494.             int 21h                 ;DOS call
  495.             mov [word 10],ax        ;Set byte count
  496.  
  497.             xor si,si
  498.             add [word 4],cx         ;Advance buffer position
  499.             adc [word 6],si
  500.             mov [word 8],si         ;Pointer pos = 0
  501.  
  502. p1_write:   mov al,[chr]            ;AX = char
  503.             xor ah,ah
  504.             mov [16+si],al          ;Put char in buffer
  505.             inc si                  ;Advance pointer
  506.             mov [word 8],si
  507.             cmp si,[word 10]        ;Hit last byte?
  508.             jna p1_done
  509.  
  510.             inc [word 10]           ;Advance byte count
  511.             mov [byte 3],1          ;Set modify flag
  512.  
  513. p1_done:    pop dx cx bx si ds      ;Restore registers
  514.             pop bp                  ;Delete stack frame
  515.             ret 4                   ;Return
  516.  
  517. p1_error:   mov ax,-1               ;Error, return EOF
  518.             jmp p1_done
  519.  
  520. EndP        fputc
  521.  
  522. End
  523.  
  524. ~~~C_FGETC
  525. Ideal
  526.  
  527. Public      fgetc
  528.  
  529. Model Tiny
  530. CodeSeg
  531. P186
  532.  
  533. ;****************** fgetc() -- Get char from buffered file
  534. ;int fgetc(int fptr);
  535.  
  536. fptr        = bp+4
  537.  
  538. Proc        fgetc
  539.  
  540.             push bp                 ;Set up stack frame
  541.             mov bp,sp
  542.             push ds si bx cx dx     ;Save registers
  543.  
  544.             mov ds,[fptr]           ;DS = seg of file
  545.             cmp [word 14],'FI'      ;Check for signature
  546.             jne p1_error
  547.  
  548.             mov bx,[word 0]         ;BX = handle
  549.  
  550.             mov si,[word 8]         ;SI = pointer pos
  551.             mov cx,[word 12]        ;CX = buffer size
  552.             cmp si,cx               ;End of buffer?
  553.             jb p1_read              ;Jump if not
  554.  
  555.             cmp [byte 3],0          ;Modified?
  556.             je p1_skip1
  557.  
  558.             mov [byte 3],0          ;Clear modify flag
  559.  
  560.             mov ax,4200h            ;Move file ptr
  561.             mov cx,[word 6]         ;CX:DX = buffer pos
  562.             mov dx,[word 4]
  563.             int 21h                 ;DOS call
  564.  
  565.             mov ah,40h              ;Write file
  566.             mov cx,[word 12]        ;CX = bytes
  567.             mov dx,16               ;Buffer offset
  568.             int 21h                 ;DOS call
  569.  
  570. p1_skip1:   xor si,si
  571.             add [word 4],cx         ;Advance buffer position
  572.             adc [word 6],si
  573.  
  574.             mov ah,3Fh              ;Read file
  575.             mov cx,[word 12]        ;CX = bytes
  576.             mov dx,16               ;Buffer offset
  577.             int 21h                 ;DOS call
  578.             mov [word 10],ax        ;Set byte count
  579.  
  580. p1_read:    cmp si,[word 10]        ;Hit last byte?
  581.             jae p1_error
  582.  
  583.             mov al,[16+si]          ;Get char from buffer
  584.             xor ah,ah
  585.             inc si                  ;Advance pointer
  586.             mov [word 8],si
  587.  
  588. p1_done:    pop dx cx bx si ds      ;Restore registers
  589.             pop bp                  ;Delete stack frame
  590.             ret 2                   ;Return
  591.  
  592. p1_error:   mov ax,-1               ;Error, return EOF
  593.             jmp p1_done
  594.  
  595. EndP        fgetc
  596.  
  597. End
  598.  
  599. ~~~C_FSEEK
  600. Ideal
  601.  
  602. Public      fseek,ftell
  603.  
  604. Model Tiny
  605. CodeSeg
  606. P186
  607.  
  608. ;****************** fseek() -- Seek to position in buffered file
  609. ;int fseek(int fptr, long pos, int cmd);
  610.  
  611. fptr        = bp+10
  612. pos         = bp+6
  613. cmd         = bp+4
  614.  
  615. Proc        fseek
  616.  
  617.             push bp                 ;Set up stack frame
  618.             mov bp,sp
  619.             push ds bx cx dx        ;Save registers
  620.  
  621.             mov ds,[fptr]           ;DS = seg of file
  622.             cmp [word 14],'FI'      ;Check for signature
  623.             jne p1_error
  624.  
  625.             mov bx,[word 0]         ;BX = handle
  626.  
  627.             cmp [byte 2],0          ;Read only, can't write buffer
  628.             je p1_seek
  629.  
  630.             mov ax,4200h            ;Move file ptr
  631.             mov cx,[word 6]         ;CX:DX = buffer pos
  632.             mov dx,[word 4]
  633.             int 21h                 ;DOS call
  634.  
  635.             mov ah,40h              ;Write file
  636.             mov cx,[word 10]        ;CX = bytes
  637.             mov dx,16               ;Buffer offset
  638.             int 21h                 ;DOS call
  639.  
  640. p1_seek:    mov ax,4200h            ;Move file ptr
  641.             mov cx,[word 6]         ;CX:DX = current pos
  642.             mov dx,[word 4]         ; = buffer pos + pointer
  643.             add dx,[word 8]
  644.             adc cx,0
  645.             int 21h                 ;DOS call
  646.  
  647.             mov ah,42h              ;Move file ptr
  648.             mov al,[cmd]            ;AL = command
  649.             mov cx,[pos+2]          ;CX:DX = new pos
  650.             mov dx,[pos]
  651.             int 21h                 ;DOS call
  652.  
  653.             mov [word 6],dx         ;Save position
  654.             mov [word 4],ax
  655.  
  656.             mov ah,3Fh              ;Read file
  657.             mov cx,[word 12]        ;CX = bytes
  658.             mov dx,16               ;Buffer offset
  659.             int 21h                 ;DOS call
  660.  
  661.             mov [word 10],ax        ;Set byte count
  662.             mov [word 8],0          ;Pointer = 0
  663.             mov ax,1                ;return 1: success
  664.  
  665. p1_done:    pop dx cx bx ds         ;Restore registers
  666.             pop bp                  ;Delete stack frame
  667.             ret 8                   ;Return
  668.  
  669. p1_error:   xor ax,ax               ;Error, return 0
  670.             jmp p1_done
  671.  
  672. EndP        fseek
  673.  
  674. ;****************** ftell() -- Return pointer in buffered file
  675. ;long ftell(int fptr);
  676.  
  677. fptr        = bp+4
  678.  
  679. Proc        ftell
  680.  
  681.             push bp                 ;Set up stack frame
  682.             mov bp,sp
  683.             push ds                 ;Save registers
  684.  
  685.             mov ds,[fptr]           ;DS = seg of file
  686.             cmp [word 14],'FI'      ;Check for signature
  687.             jne p2_error
  688.  
  689.             mov dx,[word 6]         ;DX:AX = current pos
  690.             mov ax,[word 4]         ; = buffer pos + pointer
  691.             add ax,[word 8]
  692.             adc dx,0
  693.  
  694. p2_done:    pop ds                  ;Restore registers
  695.             pop bp                  ;Delete stack frame
  696.             ret 2                   ;Return
  697.  
  698. p2_error:   xor ax,ax               ;Error, return 0
  699.             xor dx,dx
  700.             jmp p2_done
  701.  
  702. EndP        ftell
  703.  
  704. End
  705.  
  706. ~~~C_FREAD
  707. Ideal
  708.  
  709. Extrn       fgetc:near
  710. Public      fread
  711.  
  712. Model Tiny
  713. CodeSeg
  714. P186
  715.  
  716. ;****************** fread() -- Read block from buffered file
  717. ;int fread(int fptr, int nbytes, void *buf);
  718.  
  719. fptr        = bp+8
  720. nbytes      = bp+6
  721. buf         = bp+4
  722.  
  723. Proc        fread
  724.  
  725.             push bp                 ;Set up stack frame
  726.             mov bp,sp
  727.             push bx cx di           ;Save registers
  728.  
  729.             mov bx,[fptr]           ;BX = file ptr
  730.             mov cx,[nbytes]         ;CX = num. of bytes
  731.             mov di,[buf]            ;DI = buffer ptr
  732.             jcxz p1_done            ;Zero bytes, do nothing
  733.  
  734. p1_loop:    push bx                 ;Get char
  735.             call fgetc
  736.             test ax,ax              ;Check for errors
  737.             jl p1_done
  738.             mov [di],al             ;Store byte
  739.             inc di
  740.             loop p1_loop            ;Loop back
  741.  
  742. p1_done:    sub di,[buf]            ;AX = byte count
  743.             xchg ax,di
  744.  
  745.             pop di cx bx            ;Restore registers
  746.             pop bp                  ;Delete stack frame
  747.             ret 6                   ;Return
  748.  
  749. EndP        fread
  750.  
  751. End
  752.  
  753. ~~~C_FWRITE
  754. Ideal
  755.  
  756. Extrn       fputc:near
  757. Public      fwrite
  758.  
  759. Model Tiny
  760. CodeSeg
  761. P186
  762.  
  763. ;****************** fwrite() -- Write block to buffered file
  764. ;int fwrite(int fptr, int nbytes, void *buf);
  765.  
  766. fptr        = bp+8
  767. nbytes      = bp+6
  768. buf         = bp+4
  769.  
  770. Proc        fwrite
  771.  
  772.             push bp                 ;Set up stack frame
  773.             mov bp,sp
  774.             push bx cx si           ;Save registers
  775.  
  776.             mov bx,[fptr]           ;BX = file ptr
  777.             mov cx,[nbytes]         ;CX = num. of bytes
  778.             mov si,[buf]            ;SI = buffer ptr
  779.             xor ax,ax               ;Fixup for zero check
  780.             jcxz p1_done            ;Zero bytes, do nothing
  781.  
  782. p1_loop:    lodsb                   ;Load byte
  783.             push bx ax              ;Write char
  784.             call fputc
  785.             test ax,ax              ;Check for errors
  786.             jl p1_done
  787.             loop p1_loop            ;Loop back
  788.  
  789. p1_done:    sub si,[buf]            ;AX = byte count
  790.             add ax,1                ;Subtract 1 if error
  791.             sbb si,0
  792.             xchg ax,si
  793.  
  794.             pop si cx bx            ;Restore registers
  795.             pop bp                  ;Delete stack frame
  796.             ret 6                   ;Return
  797.  
  798. EndP        fwrite
  799.  
  800. End
  801.  
  802. ~~~C_FTRUNC
  803. Ideal
  804.  
  805. Public      ftrunc
  806.  
  807. Model Tiny
  808. CodeSeg
  809. P186
  810.  
  811. ;****************** ftrunc() -- Truncate buffered file at current position
  812. ;int ftrunc(int fptr);
  813.  
  814. fptr        = bp+4
  815.  
  816. Proc        ftrunc
  817.  
  818.             push bp                 ;Set up stack frame
  819.             mov bp,sp
  820.             push ds bx cx dx        ;Save registers
  821.  
  822.             mov ds,[fptr]           ;DS = seg of file
  823.             cmp [word 14],'FI'      ;Check for signature
  824.             jne p1_error
  825.  
  826.             cmp [byte 2],0          ;Read only, can't truncate
  827.             je p1_error
  828.  
  829.             mov bx,[word 0]         ;BX = handle
  830.  
  831.             mov ax,4200h            ;Move file ptr
  832.             mov cx,[word 6]         ;CX:DX = current pos
  833.             mov dx,[word 4]         ; = buffer pos + pointer
  834.             add dx,[word 8]
  835.             adc cx,0
  836.             int 21h                 ;DOS call
  837.  
  838.             mov ah,40h              ;Write 0 bytes to file
  839.             xor cx,cx               ;this truncates the file
  840.             int 21h
  841.  
  842.             mov [byte 3],1          ;Set modify flag
  843.             mov ax,[word 8]         ;Now, byte count = pointer + 1
  844.             inc ax
  845.             mov [word 10],ax
  846.             mov ax,1                ;return 1: success
  847.  
  848. p1_done:    pop dx cx bx ds         ;Restore registers
  849.             pop bp                  ;Delete stack frame
  850.             ret 2                   ;Return
  851.  
  852. p1_error:   xor ax,ax               ;Error, return 0
  853.             jmp p1_done
  854.  
  855. EndP        ftrunc
  856.  
  857. End
  858.  
  859. ~~~C_DELMOV
  860. Ideal
  861.  
  862. Public      fdel,fmove
  863.  
  864. Model Tiny
  865. CodeSeg
  866. P186
  867.  
  868. ;****************** fdel() -- Delete a file
  869. ;int fdel(char *strp);
  870.  
  871. strp        equ bp+4
  872.  
  873. Proc        fdel
  874.  
  875.             push bp                 ;Set up stack frame
  876.             mov bp,sp
  877.             push dx                 ;Save DX
  878.  
  879.             mov ah,41h              ;Delete file
  880.             mov dx,[strp]           ;DX = string pointer
  881.             int 21h                 ;DOS call
  882.  
  883.             db 0D6h                 ;SETALC (TASM doesn't recognize it)
  884.             cbw                     ;AX = 1 if ok, 0 if error
  885.             inc ax
  886.  
  887.             pop dx                  ;Restore DX
  888.             pop bp                  ;Delete stack frame
  889.             ret 2                   ;Return
  890.  
  891. EndP        fdel
  892.  
  893. ;****************** fmove() -- Move and/or rename a file
  894. ;int fmove(char *str1, char *str2);
  895.  
  896. str1        equ bp+6
  897. str2        equ bp+4
  898.  
  899. Proc        fmove
  900.  
  901.             push bp                 ;Set up stack frame
  902.             mov bp,sp
  903.             push es dx di           ;Save registers
  904.  
  905.             mov ah,56h              ;Move file
  906.             mov dx,[str1]           ;DX = old name
  907.             push ds                 ;ES = DS
  908.             pop es
  909.             mov di,[str2]           ;ES:DI = new name
  910.             int 21h                 ;DOS call
  911.  
  912.             db 0D6h                 ;SETALC (TASM doesn't recognize it)
  913.             cbw                     ;AX = 1 if ok, 0 if error
  914.             inc ax
  915.  
  916.             pop di dx es            ;Restore registers
  917.             pop bp                  ;Delete stack frame
  918.             ret 4                   ;Return
  919.  
  920. EndP        fmove
  921.  
  922. End
  923.  
  924. ~~~C_DIRECT
  925. Ideal
  926.  
  927. Public      getdir,setdir,mkdir,rmdir
  928.  
  929. Model Tiny
  930. CodeSeg
  931. P186
  932.  
  933. ;****************** getdir() -- Get current directory
  934. ;void getdir(char *strp);
  935.  
  936. strp        equ bp+4
  937.  
  938. Proc        getdir
  939.  
  940.             push bp                 ;Set up stack frame
  941.             mov bp,sp
  942.             pusha                   ;Save registers
  943.  
  944.             mov ah,19h              ;Get current drive
  945.             int 21h                 ;DOS call
  946.  
  947.             mov dl,al               ;DL = drive
  948.             mov ah,47h              ;Get current directory
  949.             mov si,[strp]           ;SI = string pointer
  950.             mov [byte si],'\'       ;Add leading slash
  951.             inc si
  952.             int 21h                 ;DOS call
  953.  
  954.             popa                    ;Restore registers
  955.             pop bp                  ;Delete stack frame
  956.             ret 2                   ;Return
  957.  
  958. EndP        getdir
  959.  
  960. ;****************** DIRcall -- Internal: used by setdir,mkdir,rmdir
  961. ;void DIRcall(void);
  962.  
  963. strp        equ bp+4
  964.  
  965. Proc        DIRcall
  966.  
  967.             push dx                 ;Save DX
  968.             mov dx,[strp]           ;DX = string pointer
  969.             int 21h                 ;DOS call
  970.  
  971.             db 0D6h                 ;SETALC (TASM doesn't recognize it)
  972.             cbw                     ;AX = 1 if ok, 0 if error
  973.             inc ax
  974.  
  975.             pop dx                  ;Restore DX
  976.             ret                     ;Return
  977.  
  978. EndP        DIRcall
  979.  
  980. ;****************** setdir() -- Set current directory
  981. ;int setdir(char *strp);
  982.  
  983. strp        equ bp+4
  984.  
  985. Proc        setdir
  986.  
  987.             push bp                 ;Set up stack frame
  988.             mov bp,sp
  989.  
  990.             mov ah,3Bh              ;Set current directory
  991.             call DIRcall            ;Directory call
  992.  
  993.             pop bp                  ;Delete stack frame
  994.             ret 2                   ;Return
  995.  
  996. EndP        setdir
  997.  
  998. ;****************** mkdir() -- Create a directory
  999. ;int mkdir(char *strp);
  1000.  
  1001. strp        equ bp+4
  1002.  
  1003. Proc        mkdir
  1004.  
  1005.             push bp                 ;Set up stack frame
  1006.             mov bp,sp
  1007.  
  1008.             mov ah,39h              ;Create directory
  1009.             call DIRcall            ;Directory call
  1010.  
  1011.             pop bp                  ;Delete stack frame
  1012.             ret 2                   ;Return
  1013.  
  1014. EndP        mkdir
  1015.  
  1016. ;****************** rmdir() -- Remove a directory
  1017. ;int rmdir(char *strp);
  1018.  
  1019. strp        equ bp+4
  1020.  
  1021. Proc        rmdir
  1022.  
  1023.             push bp                 ;Set up stack frame
  1024.             mov bp,sp
  1025.  
  1026.             mov ah,3Ah              ;Remove directory
  1027.             call DIRcall            ;Directory call
  1028.  
  1029.             pop bp                  ;Delete stack frame
  1030.             ret 2                   ;Return
  1031.  
  1032. EndP        rmdir
  1033.  
  1034. End
  1035.  
  1036. ~~~C_DRIVE
  1037. Ideal
  1038.  
  1039. Public      getdrive,setdrive
  1040.  
  1041. Model Tiny
  1042. CodeSeg
  1043. P186
  1044.  
  1045. ;****************** getdrive() -- Get current drive
  1046. ;int getdrive(void);
  1047.  
  1048. Proc        getdrive
  1049.  
  1050.             mov ah,19h              ;Get current drive
  1051.             int 21h
  1052.             xor ah,ah               ;Zero AH
  1053.             ret                     ;Return
  1054.  
  1055. EndP        getdrive
  1056.  
  1057. ;****************** setdrive() -- set current drive
  1058. ;void setdrive(int drnum);
  1059.  
  1060. drnum       equ bp+4
  1061.  
  1062. Proc        setdrive
  1063.  
  1064.             push bp                 ;Set up stack frame
  1065.             mov bp,sp
  1066.             pusha                   ;Save registers
  1067.  
  1068.             mov ah,0Eh              ;Set current drive
  1069.             mov dl,[drnum]          ;DL = drive number
  1070.             int 21h
  1071.  
  1072.             popa                    ;Restore registers
  1073.             pop bp                  ;Delete stack frame
  1074.             ret 2                   ;Return
  1075.  
  1076. EndP        setdrive
  1077.  
  1078. End
  1079.  
  1080. ~~~C_DFREE
  1081. Ideal
  1082.  
  1083. Public      getdfree
  1084.  
  1085. Model Tiny
  1086. CodeSeg
  1087. P186
  1088.  
  1089. ;****************** getdfree() -- Return amount of free disk space
  1090. ;long getdfree(int drive);
  1091.  
  1092. drive       equ bp+4
  1093.  
  1094. Proc        getdfree
  1095.  
  1096.             push bp                 ;Set up stack frame
  1097.             mov bp,sp
  1098.             push bx cx              ;Save registers
  1099.  
  1100.             mov dl,[drive]          ;DL = drive
  1101.             mov ah,36h              ;Get free disk space
  1102.             int 21h
  1103.  
  1104.             cbw                     ;DX:AX = AX
  1105.             cmp ax,-1               ;Invalid, return -1
  1106.             je p1_done
  1107.  
  1108.             mul cx                  ;DX:AX = free disk space
  1109.             mul bx                  ; = bytes/sector * sectors/a-unit
  1110.                                     ; * free a-units (allocation units)
  1111.  
  1112. p1_done:    pop cx bx               ;Restore registers
  1113.             pop bp                  ;Delete stack frame
  1114.             ret                     ;Return
  1115.  
  1116. EndP        getdfree
  1117.  
  1118. End
  1119.  
  1120. ~~~C_EXEC
  1121. Ideal
  1122.  
  1123. Extrn       allocmem:near,freemem:near
  1124. Public      exec
  1125.  
  1126. Model Tiny
  1127. CodeSeg
  1128. P186
  1129.  
  1130. ;****************** exec() -- Execute program
  1131. ;int exec(char *prog, char *cmdline);
  1132.  
  1133. prog        equ bp+6
  1134. cmdline     equ bp+4
  1135.  
  1136. Proc        exec
  1137.  
  1138.             push bp                 ;Set up stack frame
  1139.             mov bp,sp
  1140.             push ds es              ;Save all registers
  1141.             pusha
  1142.  
  1143.             push 128                ;Allocate memory for
  1144.             call allocmem           ;the cmdline buffer
  1145.             test ax,ax              ;Out of memory?
  1146.             je p1_done
  1147.             xchg bx,ax              ;Pointer in BX
  1148.  
  1149.             mov si,[prog]           ;SI = program specification
  1150.  
  1151. p1_loop1:   lodsb                   ;Skip past initial spaces
  1152.             cmp al,' '
  1153.             je p1_loop1
  1154.             dec si
  1155.             push si                 ;Save prog string offset
  1156.  
  1157.             mov si,[cmdline]        ;SI = command line
  1158.             mov di,bx               ;DI = string buffer
  1159.             inc di
  1160.             mov cx,126              ;CX = 126
  1161.  
  1162. p1_loop3:   lodsb                   ;Copy the string and
  1163.             test al,al              ;count the chars
  1164.             je p1_cont
  1165.             stosb
  1166.             loop p1_loop3
  1167.  
  1168. p1_cont:    neg cx                  ;CX = char count
  1169.             add cx,126
  1170.             mov [bx],cl             ;Store count
  1171.             mov al,13               ;Store a CR
  1172.             stosb
  1173.  
  1174.             mov ax,[2Eh]            ;word 0 = environment
  1175.             mov [ParBlock],ax
  1176.             mov [ParBlock+2],bx     ;word 2 = command line
  1177.             mov [ParBlock+4],cs     ;word 4 = CS
  1178.             mov [ParBlock+6],5Ch    ;word 6 = 5Ch
  1179.             mov [ParBlock+8],cs     ;word 8 = CS
  1180.             mov [ParBlock+10],6Ch   ;word 10 = 6Ch
  1181.             mov [ParBlock+12],cs    ;word 12 = CS
  1182.  
  1183.             push bx                 ;Save memory pointer
  1184.  
  1185.             push ds                 ;ES:BX = parameter block
  1186.             pop es
  1187.             mov bx,offset ParBlock
  1188.             pop dx                  ;DX = program specification
  1189.             mov ax,4B00h            ;DOS EXEC function
  1190.  
  1191.             mov [StackBuf],ss       ;Save stack pointer
  1192.             mov [StackBuf+2],sp
  1193.  
  1194.             int 21h                 ;Execute program
  1195.  
  1196.             mov ss,[cs:StackBuf]    ;Restore stack pointer
  1197.             mov sp,[cs:StackBuf+2]
  1198.  
  1199.             db 0D6h                 ;SETALC (TASM doesn't recognize it)
  1200.             cbw                     ;AX = 1 if ok, 0 if error
  1201.             inc ax
  1202.  
  1203.             call freemem            ;Free the memory (BX is still pushed)
  1204.  
  1205. p1_done:    mov es,ax               ;Save AX in ES
  1206.             popa                    ;Restore general registers
  1207.             mov ax,es               ;Restore AX
  1208.             pop es ds               ;Restore segment registers
  1209.             pop bp                  ;Delete stack frame
  1210.             ret 4                   ;Return
  1211.  
  1212. StackBuf    dw 0,0                  ;Save area for SS:SP
  1213.  
  1214. ParBlock    dw 7 dup(0)             ;EXEC parameter block
  1215.  
  1216. EndP        exec
  1217.  
  1218. End
  1219.  
  1220. ~~~C_BITIO
  1221. Ideal
  1222.  
  1223. Extrn       fopen:near,fclose:near,fgetc:near,fputc:near
  1224. Public      bfopen, bfclose, putbit, getbit
  1225. Public      putbits, getbits, putcode, getcode
  1226.  
  1227. Model Tiny
  1228. P186
  1229. CodeSeg
  1230.  
  1231. ;****************** Bit-File Structure . . .
  1232.  
  1233. ;                   Offset  Size    Description
  1234.  
  1235. ;                     0     Word    File handle
  1236. ;                     2     Word    File mode
  1237. ;                     4     Byte    Bit buffer
  1238. ;                     5     Byte    Bit mask
  1239.  
  1240. ;****************** bfopen() -- Open bit-file (returns bit handle)
  1241. ;                               Modes: 0 = read, 1 = write
  1242. ;int bfopen(char *fname, int mode);
  1243.  
  1244. fname       equ bp+6
  1245. mode        equ bp+4
  1246.  
  1247. Proc        bfopen
  1248.  
  1249.             push bp                 ;Set up stack frame
  1250.             mov bp,sp
  1251.             push ds bx cx dx        ;Save registers
  1252.  
  1253.             mov bx,[mode]           ;BX = mode
  1254.             and bx,1
  1255.             mov cx,bx               ;Save mode
  1256.             imul bx,3               ;Mode for fopen()
  1257.  
  1258.             push [fname] bx         ;Open the file
  1259.             call fopen
  1260.             test ax,ax              ;Check for errors
  1261.             jz p1_err1
  1262.             xchg dx,ax              ;DX = file
  1263.  
  1264.             mov ah,48h              ;Allocate memory
  1265.             mov bx,1                ;16 bytes
  1266.             int 21h                 ;DOS call
  1267.             jc p1_err2              ;Check for errors
  1268.  
  1269.             mov ds,ax               ;DS = bit-file
  1270.             mov [0],dx              ;Set file handle...
  1271.             mov [2],cx              ;file mode...
  1272.             mov [word 4],8000h      ;buffer/mask...
  1273.  
  1274. p1_done:    pop dx cx bx ds         ;Restore registers
  1275.             pop bp                  ;Delete stack frame
  1276.             ret 4                   ;Return
  1277.  
  1278. p1_err2:    push dx                 ;Out of memory, close file
  1279.             call fclose
  1280.  
  1281. p1_err1:    xor ax,ax               ;Error, return 0
  1282.             jmp p1_done
  1283.  
  1284. EndP        bfopen
  1285.  
  1286. ;****************** bfclose() -- Close bit-file
  1287. ;void bfclose(int bfp);
  1288.  
  1289. bfp         equ bp+4
  1290.  
  1291. Proc        bfclose
  1292.  
  1293.             push bp                 ;Set up stack frame
  1294.             mov bp,sp
  1295.             pusha                   ;Save all registers
  1296.             push es
  1297.  
  1298.             mov es,[bfp]            ;ES = bit-file
  1299.  
  1300.             cmp [word es:2],1       ;Input file?
  1301.             jne p2_skip
  1302.             cmp [byte es:5],80h     ;Buffer empty?
  1303.             je p2_skip
  1304.  
  1305.             push [es:0] [es:4]      ;Flush buffer
  1306.             call fputc
  1307.  
  1308. p2_skip:    push [es:0]             ;Close file
  1309.             call fclose
  1310.             mov ah,49h              ;Free memory
  1311.             int 21h
  1312.  
  1313.             pop es                  ;Restore registers
  1314.             popa
  1315.             pop bp                  ;Delete stack frame
  1316.             ret 2                   ;Return
  1317.  
  1318. EndP        bfclose
  1319.  
  1320. ;****************** getbit() -- Get bit from bit-file
  1321. ;int getbit(int bfp);
  1322.  
  1323. bfp         equ bp+4
  1324.  
  1325. Proc        getbit
  1326.  
  1327.             push bp                 ;Set up stack frame
  1328.             mov bp,sp
  1329.             push es                 ;Save registers
  1330.  
  1331.             mov es,[bfp]            ;ES = bit-file
  1332.             cmp [word es:2],0       ;Output file, can't input
  1333.             jne p3_done
  1334.             cmp [byte es:5],80h     ;Buffer empty?
  1335.             jne p3_skip1
  1336.  
  1337.             push [es:0]             ;Get char
  1338.             call fgetc
  1339.             mov [es:4],al           ;Save char
  1340.  
  1341. p3_skip1:   mov al,[es:4]           ;Get bit
  1342.             and al,[es:5]
  1343.             ror [byte es:5],1       ;Move to next bit
  1344.  
  1345.             test al,al              ;AX = 1 if nonzero,
  1346.             jz $+4                  ;or 0 if zero
  1347.             mov al,1
  1348.             cbw
  1349.  
  1350. p3_done:    pop es                  ;Restore registers
  1351.             pop bp                  ;Delete stack frame
  1352.             ret 2                   ;Return
  1353.  
  1354. EndP        getbit
  1355.  
  1356. ;****************** putbit() -- Put bit to bit-file
  1357. ;void putbit(int bfp, int bit);
  1358.  
  1359. bfp         equ bp+6
  1360. bit         equ bp+4
  1361.  
  1362. Proc        putbit
  1363.  
  1364.             push bp                 ;Set up stack frame
  1365.             mov bp,sp
  1366.             pusha                   ;Save all registers
  1367.             push es
  1368.  
  1369.             mov es,[bfp]            ;ES = bit-file
  1370.             cmp [word es:2],1       ;Input file, can't output
  1371.             jne p4_done
  1372.  
  1373.             cmp [word bit],0        ;Check bit
  1374.             jz p4_skip
  1375.             mov al,[es:5]           ;Add bit to buffer
  1376.             or [es:4],al
  1377.  
  1378. p4_skip:    shr [byte es:5],1       ;Move to next bit
  1379.             jnz p4_done             ;Finished a byte?
  1380.  
  1381.             push [es:0] [es:4]      ;Put byte to file
  1382.             call fputc
  1383.             mov [word es:4],8000h   ;Buf = 0, Mask = 80h
  1384.  
  1385. p4_done:    pop es                  ;Restore registers
  1386.             popa
  1387.             pop bp                  ;Delete stack frame
  1388.             ret 4                   ;Return
  1389.  
  1390. EndP        putbit
  1391.  
  1392. ;****************** getbits() -- Get bits from bit-file
  1393. ;int getbits(int bfp, int count);
  1394.  
  1395. bfp         equ bp+6
  1396. count       equ bp+4
  1397.  
  1398. Proc        getbits
  1399.  
  1400.             push bp                 ;Set up stack frame
  1401.             mov bp,sp
  1402.             push es cx dx           ;Save registers
  1403.  
  1404.             mov es,[bfp]            ;ES = bit-file
  1405.             cmp [word es:2],0       ;Output file, can't input
  1406.             jne p5_done
  1407.  
  1408.             mov cx,[count]          ;CX = bit count
  1409.             xor dx,dx               ;Zero buffer
  1410.  
  1411. p5_loop:    cmp [byte es:5],80h     ;Buffer empty?
  1412.             jne p5_skip1
  1413.  
  1414.             push [es:0]             ;Get char
  1415.             call fgetc
  1416.             mov [es:4],al           ;Save char
  1417.  
  1418. p5_skip1:   mov al,[es:4]           ;Get bit
  1419.             and al,[es:5]
  1420.             ror [byte es:5],1       ;Move to next bit
  1421.  
  1422. p5_skip2:   add dx,dx               ;Shift over
  1423.             test al,al              ;If bit = 1,
  1424.             jz $+3                  ;then add it in
  1425.             inc dx
  1426.             loop p5_loop            ;Loop back
  1427.  
  1428.             xchg ax,dx              ;AX = result
  1429.  
  1430. p5_done:    pop dx cx es            ;Restore registers
  1431.             pop bp                  ;Delete stack frame
  1432.             ret 4                   ;Return
  1433.  
  1434. EndP        getbits
  1435.  
  1436. ;****************** putbits() -- Put bits to bit-file
  1437. ;int putbits(int bfp, int code, int count);
  1438.  
  1439. bfp         equ bp+8
  1440. code        equ bp+6
  1441. count       equ bp+4
  1442.  
  1443. Proc        putbits
  1444.  
  1445.             push bp                 ;Set up stack frame
  1446.             mov bp,sp
  1447.             pusha                   ;Save all registers
  1448.  
  1449.             mov bx,[bfp]            ;BX = bit-file
  1450.             mov cx,[count]          ;CX = bit count
  1451.             mov dx,[code]           ;DX = code
  1452.             ror dx,cl               ;Put at left
  1453.  
  1454. p6_loop:    add dx,dx               ;Shift out bit
  1455.             sbb ax,ax               ;AX = bit
  1456.             push bx ax              ;Put bit
  1457.             call putbit
  1458.             loop p6_loop            ;Loop back
  1459.  
  1460.             popa                    ;Restore registers
  1461.             pop bp                  ;Delete stack frame
  1462.             ret 6                   ;Return
  1463.  
  1464. EndP        putbits
  1465.  
  1466. ;****************** getcode() -- Get optimal code from bit-file
  1467. ;int getcode(int bfp, int max);  'max' is number of possible codes
  1468.  
  1469. bfp         equ bp+6
  1470. max         equ bp+4
  1471.  
  1472. Proc        getcode
  1473.  
  1474.             push bp                 ;Set up stack frame
  1475.             mov bp,sp
  1476.             push bx cx dx si        ;Save registers
  1477.  
  1478.             mov ax,17               ;Set up for log
  1479.             mov cx,[max]
  1480.             jcxz p7_done            ;Quit on 0
  1481.  
  1482. p7_bloop:   dec ax                  ;AX = log2(max) + 1
  1483.             add cx,cx
  1484.             jnc p7_bloop
  1485.             xchg ax,cx              ;CX = AX
  1486.  
  1487.             mov si,1                ;SI = 2^CX - max
  1488.             shl si,cl
  1489.             sub si,[max]
  1490.  
  1491.             mov bx,[bfp]            ;BX = bit-file
  1492.             dec cx                  ;CX = count (log2(max))
  1493.  
  1494.             push bx cx              ;Get bits
  1495.             call getbits
  1496.             xchg ax,dx              ;Result in DX
  1497.  
  1498.             cmp dx,si               ;DX >= SI?
  1499.             jb p7_done
  1500.  
  1501.             push bx                 ;Add in another bit
  1502.             call getbit
  1503.             add dx,dx
  1504.             add dx,ax
  1505.             sub dx,si               ;Subtract out SI
  1506.  
  1507. p7_done:    xchg ax,dx              ;AX = result
  1508.             pop si dx cx bx         ;Restore registers
  1509.             pop bp                  ;Delete stack frame
  1510.             ret 4                   ;Return
  1511.  
  1512. EndP        getcode
  1513.  
  1514. ;****************** putcode() -- Put optimal code to bit-file
  1515. ;                                'max' is number of possible codes
  1516. ;int putcode(int bfp, int code, int max);
  1517.  
  1518. bfp         equ bp+8
  1519. code        equ bp+6
  1520. max         equ bp+4
  1521.  
  1522. Proc        putcode
  1523.  
  1524.             push bp                 ;Set up stack frame
  1525.             mov bp,sp
  1526.             pusha                   ;Save all registers
  1527.  
  1528.             mov ax,17               ;AX = log2(max) + 1
  1529.             mov cx,[max]
  1530.             jcxz p8_done            ;Quit on 0
  1531. p8_bloop:   dec ax
  1532.             add cx,cx
  1533.             jnc p8_bloop
  1534.             xchg ax,cx              ;CX = AX
  1535.  
  1536.             mov si,1                ;SI = 2^CX - max
  1537.             shl si,cl
  1538.             sub si,[max]
  1539.  
  1540.             mov dx,[code]           ;DX = code
  1541.             dec cx                  ;CX = bit count
  1542.  
  1543.             cmp dx,si               ;DX >= SI?
  1544.             jb p8_skip
  1545.             inc cx                  ;One more bit
  1546.             add dx,si               ;and add in SI
  1547.  
  1548. p8_skip:    push [bfp] dx cx        ;Output bit code
  1549.             call putbits
  1550.  
  1551. p8_done:    popa                    ;Restore registers
  1552.             pop bp                  ;Delete stack frame
  1553.             ret 4                   ;Return
  1554.  
  1555. EndP        putcode
  1556.  
  1557. End
  1558.  
  1559. ~~~C_MEMORY
  1560. Ideal
  1561.  
  1562. Extrn       TopByte:Word
  1563. Public      allocmem,freemem,getmfree
  1564.  
  1565. Model Tiny
  1566. P186
  1567. CodeSeg
  1568.  
  1569. ;****************** allocmem() -- Allocate memory
  1570. ;void *allocmem(unsigned nbytes);
  1571.  
  1572. nbytes      equ bp+4
  1573.  
  1574. Proc        allocmem
  1575.  
  1576.             push bp                 ;Set up stack frame
  1577.             mov bp,sp
  1578.             push es                 ;Save registers
  1579.             pusha
  1580.  
  1581.             mov dx,[bp+4]           ;DX = num. of bytes + 3
  1582.             add dx,3
  1583.             mov bx,offset TopByte   ;BX = first MCB
  1584.  
  1585. p1_loop:    mov cl,[bx+2]           ;CX = flag byte
  1586.             test cl,1               ;Not free, loop
  1587.             jnz p1_lb
  1588.             mov ax,[bx]             ;AX = size
  1589.             cmp ax,dx               ;Big enough?
  1590.             jae p1_gotit
  1591.  
  1592. p1_lb:      test cl,2               ;Last block?
  1593.             jnz p1_nope             ;Out of memory
  1594.             add bx,[bx]             ;Next block
  1595.             jmp p1_loop             ;Loop back
  1596.  
  1597. p1_gotit:   sub ax,3                ;Check for snug fit,
  1598.             cmp ax,dx               ;that is, too little
  1599.             jbe p1_snug             ;excess to split it
  1600.  
  1601.             sub ax,dx               ;AX = excess
  1602.             add ax,3
  1603.  
  1604.             mov si,bx               ;SI = split point
  1605.             add si,dx
  1606.             mov [si],ax             ;Set size of excess block
  1607.             mov [si+2],cl           ;Set flags to original values
  1608.  
  1609.             mov [bx],dx             ;Set size of present block
  1610.             mov [byte bx+2],1       ;Set flags: allocated, not last
  1611.             jmp p1_finish
  1612.  
  1613. p1_snug:    or [byte bx+2],1        ;Set allocated flag
  1614.  
  1615. p1_finish:  add bx,3                ;BX = offset of memory block
  1616.  
  1617. p1_done:    mov es,bx               ;ES = result
  1618.             popa                    ;Restore registers
  1619.             mov ax,es               ;Result in AX
  1620.             pop es
  1621.             pop bp                  ;Delete stack frame
  1622.             ret 2                   ;Return
  1623.  
  1624. p1_nope:    xor bx,bx               ;Return null pointer
  1625.             jmp p1_done
  1626.  
  1627. EndP        allocmem
  1628.  
  1629. ;****************** freemem() -- Free memory
  1630. ;void freemem(void *ptr);
  1631.  
  1632. ptr         equ bp+4
  1633.  
  1634. Proc        freemem
  1635.  
  1636.             push bp                 ;Set up stack frame
  1637.             mov bp,sp
  1638.             pusha                   ;Save registers
  1639.  
  1640.             mov dx,[ptr]            ;DX = pointer
  1641.             sub dx,3                ;Point to MCB
  1642.             mov bx,offset TopByte   ;BX = first MCB
  1643.             xor si,si               ;Zero previous ptr.
  1644.  
  1645. p2_loop:    cmp bx,dx               ;Found it?
  1646.             je p2_gotit
  1647.  
  1648.             test [byte bx+2],2      ;Last block?
  1649.             jnz p2_done
  1650.             mov si,bx               ;Save block
  1651.             add bx,[bx]             ;Next block
  1652.             jmp p2_loop             ;Loop back
  1653.  
  1654. p2_gotit:   mov di,bx               ;DI = next block
  1655.             add di,[bx]
  1656.  
  1657.             test [byte bx+2],2      ;Next block allocated
  1658.             jnz p2_cont1            ;or nonexistent, can't
  1659.             mov cl,[di+2]           ;merge with it
  1660.             test cl,1
  1661.             jnz p2_done
  1662.  
  1663.             mov ax,[di]             ;Merge blocks: sum sizes,
  1664.             add [bx],ax             ;set flags of second one
  1665.             mov [bx+2],cl
  1666.  
  1667. p2_cont1:   and [byte bx+2],0FEh    ;Reset allocated flag
  1668.  
  1669.             test si,si              ;Prev. block allocated
  1670.             jz p2_done              ;or nonexistent, can't
  1671.             mov cl,[si+2]           ;merge with it
  1672.             test cl,1
  1673.             jnz p2_done
  1674.  
  1675.             mov ax,[bx]            ;Merge blocks: sum sizes,
  1676.             add [si],ax            ;set flags of second one
  1677.             mov cl,[bx+2]
  1678.             mov [si],cl
  1679.  
  1680. p2_done:    popa                    ;Restore registers
  1681.             pop bp                  ;Delete stack frame
  1682.             ret 2                   ;Return
  1683.  
  1684. EndP        freemem
  1685.  
  1686. ;****************** getmfree() -- Return largest free memory block
  1687. ;unsigned getmfree(void);
  1688.  
  1689. ptr         equ bp+4
  1690.  
  1691. Proc        getmfree
  1692.  
  1693.             push bp                 ;Set up stack frame
  1694.             mov bp,sp
  1695.             push bx                 ;Save registers
  1696.  
  1697.             mov bx,offset TopByte   ;BX = first MCB
  1698.             xor ax,ax               ;Zero counter
  1699.  
  1700. p3_loop:    test [byte bx+2],1      ;Not free, skip
  1701.             jnz p3_skip
  1702.             cmp ax,[bx]             ;Biggest so far?
  1703.             jae p3_skip
  1704.             mov ax,[bx]             ;Save largest block
  1705.  
  1706. p3_skip:    test [byte bx+2],2      ;Last block?
  1707.             jnz p3_done
  1708.             add bx,[bx]             ;Next block
  1709.             jmp p3_loop             ;Loop back
  1710.  
  1711. p3_done:    sub ax,3                ;Adjust to true size
  1712.             pop bx                  ;Restore registers
  1713.             pop bp                  ;Delete stack frame
  1714.             ret                     ;Return
  1715.  
  1716. EndP        getmfree
  1717.  
  1718. End
  1719.  
  1720. ~~~C_FARMEM
  1721. Ideal
  1722.  
  1723. Public      faralloc,farfree,getfarfree
  1724.  
  1725. Model Tiny
  1726. P186
  1727. CodeSeg
  1728.  
  1729. ;****************** faralloc() -- Allocate far memory
  1730. ;int faralloc(int nparas);
  1731.  
  1732. nparas      equ bp+4
  1733.  
  1734. Proc        faralloc
  1735.  
  1736.             push bp                 ;Set up stack frame
  1737.             mov bp,sp
  1738.             push bx                 ;Save BX
  1739.  
  1740.             mov ah,48h              ;Allocate memory
  1741.             mov bx,[nparas]         ;BX = paras
  1742.             int 21h                 ;DOS call
  1743.  
  1744.             jnc $+4                 ;No error, return pointer
  1745.             xor ax,ax               ;Error, return 0
  1746.  
  1747.             pop bx                  ;Restore BX
  1748.             pop bp                  ;Delete stack frame
  1749.             ret 2                   ;Return
  1750.  
  1751. EndP        faralloc
  1752.  
  1753. ;****************** farfree() -- Free far memory
  1754. ;void farfree(int ptr);
  1755.  
  1756. ptr         equ bp+4
  1757.  
  1758. Proc        farfree
  1759.  
  1760.             push bp                 ;Set up stack frame
  1761.             mov bp,sp
  1762.             push es ax              ;Save registers
  1763.  
  1764.             mov ah,4Ah              ;Free memory
  1765.             mov es,[ptr]            ;ES = pointer
  1766.             int 21h                 ;DOS call
  1767.  
  1768.             pop ax es               ;Restore registers
  1769.             pop bp                  ;Delete stack frame
  1770.             ret 2                   ;Return
  1771.  
  1772. EndP        farfree
  1773.  
  1774. ;****************** getfarfree() -- Return largest free far memory block
  1775. ;unsigned getfarfree(void);
  1776.  
  1777. ptr         equ bp+4
  1778.  
  1779. Proc        getfarfree
  1780.  
  1781.             push bp                 ;Set up stack frame
  1782.             mov bp,sp
  1783.             push bx                 ;Save registers
  1784.  
  1785.             mov ah,48h              ;Allocate memory
  1786.             mov bx,-1               ;-1 is invalid
  1787.             int 21h                 ;DOS call (returns an error)
  1788.             xchg ax,bx              ;AX = size of largest free block
  1789.  
  1790.             pop bx                  ;Restore registers
  1791.             pop bp                  ;Delete stack frame
  1792.             ret                     ;Return
  1793.  
  1794. EndP        getfarfree
  1795.  
  1796. End
  1797.  
  1798. ~~~C_ATOI
  1799. Ideal
  1800.  
  1801. Public      atoi,atol
  1802.  
  1803. Model Tiny
  1804. CodeSeg
  1805. P186
  1806.  
  1807. ;****************** atoi() -- Convert string to int
  1808. ;int atoi(char *strp);
  1809.  
  1810. strp        equ bp+4
  1811.  
  1812. Proc        atoi
  1813.  
  1814.             push bp                 ;Set up stack frame
  1815.             mov bp,sp
  1816.  
  1817.             push dx [strp]          ;Save DX, call atol
  1818.             call atol
  1819.  
  1820.             pop dx                  ;Restore DX
  1821.             pop bp                  ;Delete stack frame
  1822.             ret 2                   ;Return
  1823.  
  1824. EndP        atoi
  1825.  
  1826. ;****************** atol() -- Convert string to long
  1827. ;long atol(char *strp);
  1828.  
  1829. strp        equ bp+4
  1830.  
  1831. Proc        atol
  1832.  
  1833.             push bp                 ;Set up stack frame
  1834.             mov bp,sp
  1835.             push bx cx si di        ;Save registers
  1836.  
  1837.             mov si,[strp]           ;SI = string
  1838.  
  1839.             xor ax,ax               ;DX:AX = 0
  1840.             xor bh,bh               ;BH = 0
  1841.             cwd
  1842.             mov cx,10               ;CX = 10
  1843.  
  1844. p1_ploop:   mov bl,[si]             ;Load char
  1845.             inc si
  1846.             cmp bl,' '              ;Loop while char is space
  1847.             je p1_ploop             ;(20h, or 09h thru 0Dh)
  1848.             cmp bl,9
  1849.             jna p1_cont
  1850.             cmp bl,13
  1851.             jbe p1_ploop
  1852.  
  1853. p1_cont:    xor bp,bp               ;BP = 0
  1854.             cmp bl,'+'              ;If char = '+', ignore
  1855.             je p1_loop
  1856.             cmp bl,'-'              ;If char <> '-', keep it
  1857.             jne p1_skip
  1858.             inc bp                  ;Set negative flag
  1859.  
  1860. p1_loop:    mov bl,[si]             ;Load char
  1861.             inc si
  1862.  
  1863. p1_skip:    cmp bl,'9'              ;Not a digit, finish
  1864.             ja p1_finish
  1865.             sub bl,'0'
  1866.             jc p1_finish
  1867.  
  1868.             mul cx                  ;Multiply by 10
  1869.             add ax,bx               ;Add in digit...
  1870.             adc dl,dh
  1871.             jz p1_loop              ;Not a long yet, loop
  1872.             jmp p1_lload            ;Go into long loop
  1873.  
  1874. p1_lloop:   mov di,dx               ;DI = old hi word
  1875.             mov cx,10               ;Multiply old lo word by 10
  1876.             mul cx
  1877.             xchg dx,cx              ;CX = new hi word(1)
  1878.             xchg ax,di              ;DI = new lo word
  1879.             mul dx                  ;Multiply old hi word by 10
  1880.             xchg ax,dx              ;DX = new hi word(2)
  1881.             xchg ax,di              ;AX = new lo word
  1882.             add ax,bx               ;Add in digit
  1883.             adc dx,cx               ;DX:AX = new value
  1884.  
  1885. p1_lload:   mov bl,[si]             ;load char
  1886.             inc si
  1887.  
  1888.             cmp bl,'9'              ;Not a digit, finish
  1889.             ja p1_finish
  1890.             sub bl,'0'
  1891.             jnc p1_lloop            ;Jump to loop
  1892.  
  1893. p1_finish:  dec bp                  ;Positive, don't negate
  1894.             jl p1_done
  1895.  
  1896.             neg dx                  ;Negate the result
  1897.             neg ax
  1898.             sbb dx,0
  1899.  
  1900. p1_done:    pop di si cx bx         ;Restore registers
  1901.             pop bp                  ;Delete stack frame
  1902.             ret 2                   ;Return
  1903.  
  1904. EndP        atol
  1905.  
  1906. End
  1907.  
  1908. ~~~C_ITOA
  1909. Ideal
  1910.  
  1911. Public      itoa
  1912.  
  1913. Model Tiny
  1914. CodeSeg
  1915. P186
  1916.  
  1917. ;****************** itoa() -- Convert int to string
  1918. ;void itoa(int n, char *strp);
  1919.  
  1920. n           equ bp+6
  1921. strp        equ bp+4
  1922.  
  1923. Proc        itoa
  1924.  
  1925.             push bp                 ;Set up stack frame
  1926.             mov bp,sp
  1927.             pusha                   ;Save all registers
  1928.  
  1929.             mov ax,[n]              ;AX = n
  1930.             mov di,[strp]           ;DI = string pointer
  1931.  
  1932.             test ax,ax              ;Negative?
  1933.             jge p1_noneg
  1934.             mov [byte di],'-'       ;Store minus sign
  1935.             inc di
  1936.             neg ax                  ;Make it positive
  1937.  
  1938. p1_noneg:   xor cx,cx               ;Zero CX
  1939.             test ax,ax              ;Check for zero
  1940.             jnz p1_nozero
  1941.  
  1942.             push '0'                ;Push a zero
  1943.             inc cx                  ;One digit
  1944.             jmp p1_ploop
  1945.  
  1946. p1_nozero:  mov si,10               ;SI = 10
  1947.  
  1948. p1_dloop:   xor dx,dx               ;Divide by 10
  1949.             div si
  1950.             mov bl,dl               ;Remainder in BL
  1951.             add bl,30h              ;Convert to digit
  1952.             push bx                 ;Push digit
  1953.             inc cx
  1954.             test ax,ax              ;Loop back
  1955.             jnz p1_dloop
  1956.  
  1957. p1_ploop:   pop ax                  ;Pop digit
  1958.             mov [di],al             ;Store digit
  1959.             inc di
  1960.             loop p1_ploop           ;Loop back
  1961.  
  1962.             mov [byte di],0         ;Add the null byte
  1963.  
  1964.             popa                    ;Restore registers
  1965.             pop bp                  ;Delete stack frame
  1966.             ret 4                   ;Return
  1967.  
  1968. EndP        itoa
  1969.  
  1970. End
  1971.  
  1972. ~~~C_LTOA
  1973. Ideal
  1974.  
  1975. Extrn       itoa:near
  1976. Public      ltoa
  1977.  
  1978. Model Tiny
  1979. CodeSeg
  1980. P186
  1981.  
  1982. ;****************** ltoa() -- Convert long to string
  1983. ;void ltoa(long n, char *strp);
  1984.  
  1985. n           equ bp+6
  1986. strp        equ bp+4
  1987.  
  1988. Proc        ltoa
  1989.  
  1990.             push bp                 ;Set up stack frame
  1991.             mov bp,sp
  1992.             pusha                   ;Save all registers
  1993.  
  1994.             mov di,[strp]           ;DI = string pointer
  1995.             mov dx,[n+2]            ;DX:AX = n
  1996.             mov ax,[n]
  1997.             test dx,dx              ;DX = 0, use itoa
  1998.             jnz p1_chkn
  1999.             cmp ax,8000h
  2000.             jnb p1_chkn
  2001.  
  2002. p1_itoa:    push ax di              ;Convert with itoa
  2003.             call itoa
  2004.             jmp p1_done             ;Return
  2005.  
  2006. p1_chkn:    cmp dx,-1               ;DX = -1 and AX <> 0, use itoa
  2007.             jne p1_strp
  2008.             cmp ax,8000h
  2009.             jae p1_itoa
  2010.  
  2011. p1_strp:    test dx,dx              ;Negative?
  2012.             jge p1_noneg
  2013.             mov [byte di],'-'       ;Store minus sign
  2014.             inc di
  2015.             neg dx                  ;Make it positive
  2016.             neg ax
  2017.             sbb dx,0
  2018.  
  2019. p1_noneg:   mov bx,50000            ;Divide by 100000
  2020.             div bx
  2021.             xor bx,bx               ;Zero BX
  2022.             shr ax,1
  2023.             adc bx,0                ;BX = rem flag
  2024.             push bx dx              ;Save BX, DX
  2025.  
  2026.             test ax,ax              ;Check for zero
  2027.             jz p1_cont
  2028.  
  2029.             xor cx,cx               ;Zero CX
  2030.             mov si,10               ;SI = 10
  2031.  
  2032. p1_dloop:   xor dx,dx               ;Divide by 10
  2033.             div si
  2034.             mov bl,dl               ;Remainder in BL
  2035.             add bl,30h              ;Convert to digit
  2036.             push bx                 ;Push digit
  2037.             inc cx
  2038.             test ax,ax              ;Loop back
  2039.             jnz p1_dloop
  2040.  
  2041. p1_ploop:   pop ax                  ;Pop digit
  2042.             mov [di],al             ;Store digit
  2043.             inc di
  2044.             loop p1_ploop           ;Loop back
  2045.  
  2046. p1_cont:    pop ax bx               ;Restore low data
  2047.             xor dx,dx               ;Zero DX
  2048.             test bx,bx              ;Check for high part
  2049.             jz p1_nohigh
  2050.  
  2051.             add ax,50000            ;Add in 50000
  2052.             adc dx,0
  2053.  
  2054. p1_nohigh:  mov si,10               ;SI = 10
  2055.             mov cx,5                ;5 digits
  2056.             jmp p1_skip1
  2057.  
  2058. p1_dloopb:  xor dx,dx               ;Zero DX
  2059. p1_skip1:   div si                  ;Divide by 10
  2060.             mov bl,dl               ;Remainder in BL
  2061.             add bl,30h              ;Convert to digit
  2062.             push bx                 ;Push digit
  2063.             loop p1_dloopb          ;Loop back
  2064.  
  2065.             mov cx,5                ;5 digits
  2066.  
  2067. p1_ploopb:  pop ax                  ;Pop digit
  2068.             mov [di],al             ;Store digit
  2069.             inc di
  2070.             loop p1_ploopb          ;Loop back
  2071.  
  2072.             mov [byte di],0         ;Add the null byte
  2073.  
  2074. p1_done:    popa                    ;Restore registers
  2075.             pop bp                  ;Delete stack frame
  2076.             ret 6                   ;Return
  2077.  
  2078. EndP        ltoa
  2079.  
  2080. End
  2081.  
  2082. ~~~C_PUTS
  2083. Ideal
  2084.  
  2085. Extrn       PUT_CHAR:near
  2086. Public      puts,xputs
  2087.  
  2088. Model Tiny
  2089. CodeSeg
  2090. P186
  2091.  
  2092. ;****************** puts() -- Print string
  2093. ;void puts(char *strp);
  2094.  
  2095. strp        equ bp+4
  2096.  
  2097. Proc        puts
  2098.  
  2099.             push bp                 ;Set up stack frame
  2100.             mov bp,sp
  2101.             pusha                   ;Save all registers
  2102.  
  2103.             mov si,[strp]           ;SI = string pointer
  2104.  
  2105. p1_loop:    lodsb                   ;Get char
  2106.             test al,al              ;Check for null
  2107.             jz p1_done
  2108.             call PUT_CHAR           ;Output char
  2109.             jmp p1_loop             ;Loop back
  2110.  
  2111. p1_done:    popa                    ;Restore registers
  2112.             pop bp                  ;Delete stack frame
  2113.             ret 2                   ;Return
  2114.  
  2115. EndP        puts
  2116.  
  2117. ;****************** xputs() -- Print string, generalized
  2118. ;void xputs(void *func, int strp);
  2119.  
  2120. func        equ bp+6
  2121. strp        equ bp+4
  2122.  
  2123. Proc        xputs
  2124.  
  2125.             push bp                 ;Set up stack frame
  2126.             mov bp,sp
  2127.             pusha                   ;Save all registers
  2128.  
  2129.             mov si,[strp]           ;SI = string pointer
  2130.             mov bx,[func]           ;BX = function
  2131.  
  2132. p2_loop:    lodsb                   ;Get char
  2133.             test al,al              ;Check for null
  2134.             jz p2_done
  2135.             push ax                 ;Output char
  2136.             call bx
  2137.             jmp p2_loop             ;Loop back
  2138.  
  2139. p2_done:    popa                    ;Restore registers
  2140.             pop bp                  ;Delete stack frame
  2141.             ret 4                   ;Return
  2142.  
  2143. EndP        xputs
  2144.  
  2145. End
  2146.  
  2147. ~~~C_FPUTS
  2148. Ideal
  2149.  
  2150. Extrn       fputc:near
  2151. Public      fputs
  2152.  
  2153. Model Tiny
  2154. CodeSeg
  2155. P186
  2156.  
  2157. ;****************** fputs() -- Print string to file
  2158. ;int fputs(int fp, char *strp);
  2159.  
  2160. fp          equ bp+6
  2161. strp        equ bp+4
  2162.  
  2163. Proc        fputs
  2164.  
  2165.             push bp                 ;Set up stack frame
  2166.             mov bp,sp
  2167.             push bx si              ;Save registers
  2168.  
  2169.             mov si,[strp]           ;SI = string pointer
  2170.             mov bx,[fp]             ;BX = file pointer
  2171.  
  2172. p1_loop:    lodsb                   ;Get char
  2173.             test al,al              ;Check for null
  2174.             jz p1_done
  2175.             push bx ax              ;Output char:
  2176.             call fputc              ;fputc(fp, AX);
  2177.             test ax,ax
  2178.             jnl p1_loop             ;Loop back
  2179.  
  2180. p1_done:    pop si bx               ;Restore registers
  2181.             pop bp                  ;Delete stack frame
  2182.             ret 4                   ;Return
  2183.  
  2184. EndP        fputs
  2185.  
  2186. End
  2187.  
  2188. ~~~C_GETS
  2189. Ideal
  2190.  
  2191. Public      gets,xgets
  2192.  
  2193. Model Tiny
  2194. CodeSeg
  2195. P186
  2196.  
  2197. ;****************** gets() -- Get string
  2198. ;void gets(char *strp, int max);
  2199.  
  2200. strp        equ bp+6
  2201. max         equ bp+4
  2202.  
  2203. Proc        gets
  2204.  
  2205.             push bp                 ;Set up stack frame
  2206.             mov bp,sp
  2207.             pusha                   ;Save all registers
  2208.             push es
  2209.  
  2210.             mov di,[strp]           ;DI = string pointer
  2211.             mov cx,[max]            ;CX = max string length
  2212.             dec cx
  2213.  
  2214. p1_loop:    xor ax,ax               ;Get key
  2215.             int 16h
  2216.             test al,al              ;Ignore extended keys
  2217.             jz p1_loop
  2218.             cmp al,8                ;Backspace?
  2219.             je p1_bksp
  2220.  
  2221.             int 29h                 ;Show char (on screen)
  2222.             cmp al,13               ;<Enter> = done
  2223.             je p1_done
  2224.             jcxz p1_loop            ;Maxed out, don't store
  2225.             mov [di],al             ;Store char
  2226.             inc di
  2227.             dec cx                  ;Decrement maximum
  2228.             jmp p1_loop             ;Loop back
  2229.  
  2230. p1_bksp:    cmp di,[strp]           ;At beginning, do nothing
  2231.             je p1_loop
  2232.             dec di                  ;Decrement string pointer
  2233.             inc cx                  ;Increment maximum
  2234.  
  2235.             push cx                 ;Save CX
  2236.             mov ah,0Fh              ;Get video page
  2237.             int 10h
  2238.             mov ah,3                ;Get cursor position
  2239.             int 10h                 ;in DH/DL
  2240.             dec dx                  ;Move left one column
  2241.             test dl,dl              ;if at zero moves up too
  2242.             jnl p1_nowrap
  2243.  
  2244.             push 0                  ;DL = last column
  2245.             pop es
  2246.             mov dl,[es:044Ah]
  2247.             dec dx
  2248.  
  2249. p1_nowrap:  mov ah,2                ;Set cursor position
  2250.             int 10h
  2251.             mov ax,0A20h            ;Clear char at current
  2252.             mov cx,1                ;cursor position
  2253.             int 10h
  2254.             pop cx                  ;Restore CX
  2255.             jmp p1_loop             ;Loop back
  2256.  
  2257. p1_done:    mov al,10               ;Output LF
  2258.             int 29h
  2259.             mov [byte di],0         ;Terminate string
  2260.             pop es                  ;Restore registers
  2261.             popa
  2262.             pop bp                  ;Delete stack frame
  2263.             ret 4                   ;Return
  2264.  
  2265. EndP        gets
  2266.  
  2267. ;****************** xgets() -- Get string, generalized
  2268. ;void xgets(void *func, char *strp, int max, int term);
  2269.  
  2270. strp        equ bp+10
  2271. func        equ bp+8
  2272. max         equ bp+6
  2273. term        equ bp+4
  2274.  
  2275. Proc        xgets
  2276.  
  2277.             push bp                 ;Set up stack frame
  2278.             mov bp,sp
  2279.             pusha                   ;Save all registers
  2280.  
  2281.             mov di,[strp]           ;DI = string pointer
  2282.             mov bx,[func]           ;BX = function
  2283.             mov cx,[max]            ;CX = max string length
  2284.             dec cx
  2285.             mov dx,[term]           ;DX = terminator
  2286.  
  2287. p2_loop:    call bx                 ;Get char
  2288.             cmp al,dl               ;Check for terminator
  2289.             je p2_done
  2290.             jcxz p1_loop            ;Maxed out, don't store
  2291.             mov [di],al             ;Store char
  2292.             inc di
  2293.             dec cx                  ;Decrement maximum
  2294.             jmp p2_loop             ;Loop back
  2295.  
  2296. p2_done:    mov [byte di],0         ;Terminate string
  2297.             popa                    ;Restore registers
  2298.             pop bp                  ;Delete stack frame
  2299.             ret 8                   ;Return
  2300.  
  2301. EndP        xgets
  2302.  
  2303. End
  2304.  
  2305. ~~~C_FGETS
  2306. Ideal
  2307.  
  2308. Extrn       fgetc:near
  2309. Public      fgets
  2310.  
  2311. Model Tiny
  2312. CodeSeg
  2313. P186
  2314.  
  2315. ;****************** fgets() -- Get string from file
  2316. ;void fgets(int fp, char *strp, int max);
  2317.  
  2318. fp          equ bp+8
  2319. strp        equ bp+6
  2320. max         equ bp+4
  2321.  
  2322. Proc        fgets
  2323.  
  2324.             push bp                 ;Set up stack frame
  2325.             mov bp,sp
  2326.             push bx cx dx di        ;Save all registers
  2327.  
  2328.             mov di,[strp]           ;DI = string pointer
  2329.             mov bx,[fp]             ;BX = file pointer
  2330.             mov cx,[max]            ;CX = max string length
  2331.             dec cx
  2332.  
  2333. p1_loop:    push bx                 ;Get char
  2334.             call fgetc
  2335.             test ax,ax              ;Check for EOF
  2336.             jl p1_quit
  2337.             cmp al,13               ;CR = done
  2338.             je p1_done
  2339.             jcxz p1_loop            ;Maxed out, don't store
  2340.             mov [di],al             ;Store char
  2341.             inc di
  2342.             dec cx                  ;Decrement maximum
  2343.             jmp p1_loop             ;Loop back
  2344.  
  2345. p1_done:    push bx                 ;Remove LF
  2346.             call fgetc
  2347.             xor ax,ax
  2348. p1_quit:    mov [byte di],0         ;Terminate string
  2349.             pop di dx cx bx         ;Restore registers
  2350.             pop bp                  ;Delete stack frame
  2351.             ret 6                   ;Return
  2352.  
  2353. EndP        fgets
  2354.  
  2355. End
  2356.  
  2357. ~~~C_PRTBUF
  2358. Ideal
  2359.  
  2360. Public      PRT_BUF
  2361.  
  2362. Model Tiny
  2363. CodeSeg
  2364. P186
  2365.  
  2366. ;****************** PRT_BUF -- String buffer for printf(), etc.
  2367.  
  2368. PRT_BUF     db 20 dup(0)
  2369.  
  2370. End
  2371.  
  2372. ~~~C_PRINTF
  2373. Ideal
  2374.  
  2375. Extrn       PRT_BUF:byte,itoa:near,ltoa:near
  2376. Extrn       PUT_CHAR:near
  2377. Public      printf
  2378.  
  2379. Model Tiny
  2380. CodeSeg
  2381. P186
  2382.  
  2383. ;****************** printf() -- Print formatted string
  2384. ;void printf(char *fmt, void *args);
  2385.  
  2386. fmt         equ bp+6
  2387. args        equ bp+4
  2388.  
  2389. Proc        printf
  2390.  
  2391.             push bp                 ;Set up stack frame
  2392.             mov bp,sp
  2393.             pusha                   ;Save all registers
  2394.  
  2395.             mov si,[fmt]            ;SI = string pointer
  2396.             mov bx,[args]           ;BX = arg pointer
  2397.  
  2398. p1_loop:    lodsb                   ;Get char
  2399.             test al,al              ;Check for null
  2400.             jz p1_done
  2401.             cmp al,'%'              ;Check for '%'
  2402.             je p1_proc
  2403. p1_putc:    call PUT_CHAR           ;Output char
  2404.             jmp p1_loop             ;Loop back
  2405.  
  2406. p1_proc:    lodsb                   ;Get char
  2407.             test al,al              ;Check for null
  2408.             jz p1_done
  2409.             cmp al,'%'              ; %% = percent
  2410.             je p1_putc
  2411.             cmp al,'d'              ; %d = integer
  2412.             je p1_int
  2413.             cmp al,'l'              ; %l = long int
  2414.             je p1_long
  2415.             cmp al,'x'              ; %x = hex
  2416.             je p1_hex
  2417.             cmp al,'c'              ; %c = char
  2418.             je p1_char
  2419.             cmp al,'s'              ; %s = string
  2420.             je p1_str
  2421.             jmp p1_loop             ;Invalid, ignore
  2422.  
  2423. p1_done:    popa                    ;Restore registers
  2424.             pop bp                  ;Delete stack frame
  2425.             ret 4                   ;Return
  2426.  
  2427. p1_long:    lodsb                   ;Get char
  2428.             test al,al              ;Check for null
  2429.             jz p1_done
  2430.             cmp al,'d'              ; %ld = long integer
  2431.             je p1_lint
  2432.             cmp al,'x'              ; %lx = long hex
  2433.             je p1_lhex
  2434.             jmp p1_loop             ;Invalid, ignore
  2435.  
  2436. p1_int:     push [word bx]          ;itoa(*bx, PRT_BUF);
  2437.             push offset PRT_BUF
  2438.             call itoa
  2439.             inc bx                  ;Advance pointer
  2440.             inc bx
  2441.             mov di,offset PRT_BUF   ;Print alpha string
  2442.             jmp p1_alpha
  2443.  
  2444. p1_lint:    push [word bx+2]
  2445.             push [word bx]          ;ltoa(*bx, PRT_BUF);
  2446.             push offset PRT_BUF
  2447.             call ltoa
  2448.             add bx,4                ;Advance pointer
  2449.             mov di,offset PRT_BUF   ;Print alpha string
  2450.             jmp p1_alpha
  2451.  
  2452. p1_hex:     mov ax,[bx]             ;AX = arg
  2453.             call p1_chex            ;Convert to hex
  2454.             inc bx                  ;Advance pointer
  2455.             inc bx
  2456.             jmp p1_loop             ;Loop back
  2457.  
  2458. p1_lhex:    mov ax,[bx+2]           ;AX = high word
  2459.             call p1_chex            ;Convert to hex
  2460.             mov ax,[bx]             ;AX = low word
  2461.             call p1_chex            ;Convert to hex
  2462.             add bx,4                ;Advance pointer
  2463.             jmp p1_loop             ;Loop back
  2464.  
  2465. p1_char:    mov al,[bx]             ;Output char
  2466.             int 29h
  2467.             inc bx                  ;Advance pointer
  2468.             jmp p1_loop             ;Loop back
  2469.  
  2470. p1_str:     mov al,[bx]             ;Get char
  2471.             inc bx                  ;Advance pointer
  2472.             test al,al              ;Check for null
  2473.             jz p1_sdone
  2474.             call PUT_CHAR           ;Output char
  2475.             jmp p1_str              ;Loop back
  2476.  
  2477. p1_sdone:   jmp p1_loop             ;Return to main loop
  2478.  
  2479. p1_alpha:   mov al,[di]             ;Get char
  2480.             test al,al              ;Check for null
  2481.             jz p1_sdone
  2482.             call PUT_CHAR           ;Output char
  2483.             inc di                  ;Advance pointer
  2484.             jmp p1_alpha            ;Loop back
  2485.  
  2486. p1_chex:    mov cx,4                ;4 hex digits
  2487.             xchg al,ah              ;Reverse the order
  2488.             ror ah,cl               ;of the hex digits
  2489.             ror al,cl               ;in AX
  2490.  
  2491. p1_hloop:   push ax                 ;Save AX
  2492.             and al,0Fh              ;Keep 4 bits
  2493.             cmp al,0Ah              ;Compute the hex digit,
  2494.             sbb al,69h              ;using Improved Allison's Algorithm
  2495.             das
  2496.             call PUT_CHAR           ;Output char
  2497.             pop ax                  ;Restore AX
  2498.             shr ax,4                ;Shift it over
  2499.             loop p1_hloop           ;Loop back
  2500.             ret                     ;Return
  2501.  
  2502. EndP        printf
  2503.  
  2504. End
  2505.  
  2506. ~~~C_SPRINT
  2507. Ideal
  2508.  
  2509. Extrn       PRT_BUF:byte,itoa:near,ltoa:near
  2510. Public      sprintf
  2511.  
  2512. Model Tiny
  2513. CodeSeg
  2514. P186
  2515.  
  2516. ;****************** sprintf() -- Print formatted string into string
  2517. ;void sprintf(char *strp, char *fmt, void *args);
  2518.  
  2519. strp        equ bp+8
  2520. fmt         equ bp+6
  2521. args        equ bp+4
  2522.  
  2523. Proc        sprintf
  2524.  
  2525.             push bp                 ;Set up stack frame
  2526.             mov bp,sp
  2527.             pusha                   ;Save all registers
  2528.  
  2529.             mov di,[strp]           ;DI = string pointer
  2530.             mov si,[fmt]            ;SI = format pointer
  2531.             mov bx,[args]           ;BX = arg pointer
  2532.  
  2533. p1_loop:    lodsb                   ;Get char
  2534.             test al,al              ;Check for null
  2535.             jz p1_done
  2536.             cmp al,'%'              ;Check for '%'
  2537.             je p1_proc
  2538. p1_putc:    stosb                   ;Output char
  2539.             jmp p1_loop             ;Loop back
  2540.  
  2541. p1_proc:    lodsb                   ;Get char
  2542.             test al,al              ;Check for null
  2543.             jz p1_done
  2544.             cmp al,'%'              ; %% = percent
  2545.             je p1_putc
  2546.             cmp al,'d'              ; %d = integer
  2547.             je p1_int
  2548.             cmp al,'l'              ; %l = long int
  2549.             je p1_long
  2550.             cmp al,'x'              ; %x = hex
  2551.             je p1_hex
  2552.             cmp al,'c'              ; %c = char
  2553.             je p1_char
  2554.             cmp al,'s'              ; %s = string
  2555.             je p1_str
  2556.             jmp p1_loop             ;Invalid, ignore
  2557.  
  2558. p1_done:    xor al,al               ;Store a null byte
  2559.             stosb
  2560.             popa                    ;Restore registers
  2561.             pop bp                  ;Delete stack frame
  2562.             ret 6                   ;Return
  2563.  
  2564. p1_long:    lodsb                   ;Get char
  2565.             test al,al              ;Check for null
  2566.             jz p1_done
  2567.             cmp al,'d'              ; %ld = long integer
  2568.             je p1_lint
  2569.             cmp al,'x'              ; %lx = long hex
  2570.             je p1_lhex
  2571.             jmp p1_loop             ;Invalid, ignore
  2572.  
  2573. p1_int:     push [word bx]          ;itoa(*bx, PRT_BUF);
  2574.             push offset PRT_BUF
  2575.             call itoa
  2576.             inc bx                  ;Advance pointer
  2577.             inc bx
  2578.             mov bp,offset PRT_BUF   ;Print alpha string
  2579.             jmp p1_alpha
  2580.  
  2581. p1_lint:    push [word bx+2]
  2582.             push [word bx]          ;ltoa(*bx, PRT_BUF);
  2583.             push offset PRT_BUF
  2584.             call ltoa
  2585.             add bx,4                ;Advance pointer
  2586.             mov bp,offset PRT_BUF   ;Print alpha string
  2587.             jmp p1_alpha
  2588.  
  2589. p1_hex:     mov ax,[bx]             ;AX = arg
  2590.             call p1_chex            ;Convert to hex
  2591.             inc bx                  ;Advance pointer
  2592.             inc bx
  2593.             jmp p1_loop             ;Loop back
  2594.  
  2595. p1_lhex:    mov ax,[bx+2]           ;AX = high word
  2596.             call p1_chex            ;Convert to hex
  2597.             mov ax,[bx]             ;AX = low word
  2598.             call p1_chex            ;Convert to hex
  2599.             add bx,4                ;Advance pointer
  2600.             jmp p1_loop             ;Loop back
  2601.  
  2602. p1_char:    mov al,[bx]             ;Output char
  2603.             stosb
  2604.             inc bx                  ;Advance pointer
  2605.             jmp p1_loop             ;Loop back
  2606.  
  2607. p1_str:     mov al,[bx]             ;Get char
  2608.             inc bx                  ;Advance pointer
  2609.             test al,al              ;Check for null
  2610.             jz p1_sdone
  2611.             stosb                   ;Output char
  2612.             jmp p1_str              ;Loop back
  2613.  
  2614. p1_sdone:   jmp p1_loop             ;Return to main loop
  2615.  
  2616. p1_alpha:   mov al,[bp]             ;Get char
  2617.             test al,al              ;Check for null
  2618.             jz p1_sdone
  2619.             stosb                   ;Output char
  2620.             inc bp                  ;Advance pointer
  2621.             jmp p1_alpha            ;Loop back
  2622.  
  2623. p1_chex:    mov cx,4                ;4 hex digits
  2624.             xchg al,ah              ;Reverse the order
  2625.             ror ah,cl               ;of the hex digits
  2626.             ror al,cl               ;in AX
  2627.  
  2628. p1_hloop:   push ax                 ;Save AX
  2629.             and al,0Fh              ;Keep 4 bits
  2630.             cmp al,0Ah              ;Compute the hex digit,
  2631.             sbb al,69h              ;using Improved Allison's Algorithm
  2632.             das
  2633.             stosb                   ;Output char
  2634.             pop ax                  ;Restore AX
  2635.             shr ax,4                ;Shift it over
  2636.             loop p1_hloop           ;Loop back
  2637.             ret                     ;Return
  2638.  
  2639. EndP        sprintf
  2640.  
  2641. End
  2642.  
  2643. ~~~C_FPRINT
  2644. Ideal
  2645.  
  2646. Extrn       PRT_BUF:byte,fputc:near,itoa:near,ltoa:near
  2647. Public      fprintf
  2648.  
  2649. Model Tiny
  2650. CodeSeg
  2651. P186
  2652.  
  2653. ;****************** fprintf() -- Print formatted string to file
  2654. ;void fprintf(int fp, char *fmt, void *args);
  2655.  
  2656. fp          equ bp+8
  2657. fmt         equ bp+6
  2658. args        equ bp+4
  2659.  
  2660. Proc        fprintf
  2661.  
  2662.             push bp                 ;Set up stack frame
  2663.             mov bp,sp
  2664.             pusha                   ;Save all registers
  2665.  
  2666.             mov dx,[fp]             ;DX = file pointer
  2667.             mov si,[fmt]            ;SI = string pointer
  2668.             mov bx,[args]           ;BX = arg pointer
  2669.  
  2670. p1_loop:    lodsb                   ;Get char
  2671.             test al,al              ;Check for null
  2672.             jz p1_done
  2673.             cmp al,'%'              ;Check for '%'
  2674.             je p1_proc
  2675. p1_putc:    push dx ax              ;Output char
  2676.             call fputc
  2677.             jmp p1_loop             ;Loop back
  2678.  
  2679. p1_proc:    lodsb                   ;Get char
  2680.             test al,al              ;Check for null
  2681.             jz p1_done
  2682.             cmp al,'%'              ; %% = percent
  2683.             je p1_putc
  2684.             cmp al,'d'              ; %d = integer
  2685.             je p1_int
  2686.             cmp al,'l'              ; %l = long int
  2687.             je p1_long
  2688.             cmp al,'x'              ; %x = hex
  2689.             je p1_hex
  2690.             cmp al,'c'              ; %c = char
  2691.             je p1_char
  2692.             cmp al,'s'              ; %s = string
  2693.             je p1_str
  2694.             jmp p1_loop             ;Invalid, ignore
  2695.  
  2696. p1_done:    popa                    ;Restore registers
  2697.             pop bp                  ;Delete stack frame
  2698.             ret 6                   ;Return
  2699.  
  2700. p1_long:    lodsb                   ;Get char
  2701.             test al,al              ;Check for null
  2702.             jz p1_done
  2703.             cmp al,'d'              ; %ld = long integer
  2704.             je p1_lint
  2705.             cmp al,'x'              ; %lx = long hex
  2706.             je p1_lhex
  2707.             jmp p1_loop             ;Invalid, ignore
  2708.  
  2709. p1_int:     push [word bx]          ;itoa(*bx, PRT_BUF);
  2710.             push offset PRT_BUF
  2711.             call itoa
  2712.             inc bx                  ;Advance pointer
  2713.             inc bx
  2714.             mov di,offset PRT_BUF   ;Print alpha string
  2715.             jmp p1_alpha
  2716.  
  2717. p1_lint:    push [word bx+2]
  2718.             push [word bx]          ;ltoa(*bx, PRT_BUF);
  2719.             push offset PRT_BUF
  2720.             call ltoa
  2721.             add bx,4                ;Advance pointer
  2722.             mov di,offset PRT_BUF   ;Print alpha string
  2723.             jmp p1_alpha
  2724.  
  2725. p1_hex:     mov ax,[bx]             ;AX = arg
  2726.             call p1_chex            ;Convert to hex
  2727.             inc bx                  ;Advance pointer
  2728.             inc bx
  2729.             jmp p1_loop             ;Loop back
  2730.  
  2731. p1_lhex:    mov ax,[bx+2]           ;AX = high word
  2732.             call p1_chex            ;Convert to hex
  2733.             mov ax,[bx]             ;AX = low word
  2734.             call p1_chex            ;Convert to hex
  2735.             add bx,4                ;Advance pointer
  2736.             jmp p1_loop             ;Loop back
  2737.  
  2738. p1_char:    mov al,[bx]             ;Output char
  2739.             push dx ax
  2740.             call fputc
  2741.             inc bx                  ;Advance pointer
  2742.             jmp p1_loop             ;Loop back
  2743.  
  2744. p1_str:     mov al,[bx]             ;Get char
  2745.             inc bx                  ;Advance pointer
  2746.             test al,al              ;Check for null
  2747.             jz p1_sdone
  2748.             push dx ax              ;Output char
  2749.             call fputc
  2750.             jmp p1_str              ;Loop back
  2751.  
  2752. p1_sdone:   jmp p1_loop             ;Return to main loop
  2753.  
  2754. p1_alpha:   mov al,[di]             ;Get char
  2755.             test al,al              ;Check for null
  2756.             jz p1_sdone
  2757.             push dx ax              ;Output char
  2758.             call fputc
  2759.             inc di                  ;Advance pointer
  2760.             jmp p1_alpha            ;Loop back
  2761.  
  2762. p1_chex:    mov cx,4                ;4 hex digits
  2763.             xchg al,ah              ;Reverse the order
  2764.             ror ah,cl               ;of the hex digits
  2765.             ror al,cl               ;in AX
  2766.  
  2767. p1_hloop:   push ax                 ;Save AX
  2768.             and al,0Fh              ;Keep 4 bits
  2769.             cmp al,0Ah              ;Compute the hex digit,
  2770.             sbb al,69h              ;using Improved Allison's Algorithm
  2771.             das
  2772.             push dx ax              ;Output char
  2773.             call fputc
  2774.             pop ax                  ;Restore AX
  2775.             shr ax,4                ;Shift it over
  2776.             loop p1_hloop           ;Loop back
  2777.             ret                     ;Return
  2778.  
  2779. EndP        fprintf
  2780.  
  2781. End
  2782.  
  2783. ~~~C_XPRINT
  2784. Ideal
  2785.  
  2786. Extrn       PRT_BUF:byte,itoa:near,ltoa:near
  2787. Public      xprintf
  2788.  
  2789. Model Tiny
  2790. CodeSeg
  2791. P186
  2792.  
  2793. ;****************** xprintf() -- Print formatted string, generalized
  2794. ;void xprintf(void *func, char *fmt, void *args);
  2795.  
  2796. func        equ bp+8
  2797. fmt         equ bp+6
  2798. args        equ bp+4
  2799.  
  2800. Proc        xprintf
  2801.  
  2802.             push bp                 ;Set up stack frame
  2803.             mov bp,sp
  2804.             pusha                   ;Save all registers
  2805.  
  2806.             mov dx,[func]           ;DX = function pointer
  2807.             mov si,[fmt]            ;SI = string pointer
  2808.             mov bx,[args]           ;BX = arg pointer
  2809.  
  2810. p1_loop:    lodsb                   ;Get char
  2811.             test al,al              ;Check for null
  2812.             jz p1_done
  2813.             cmp al,'%'              ;Check for '%'
  2814.             je p1_proc
  2815. p1_putc:    push ax                 ;Output char
  2816.             call dx
  2817.             jmp p1_loop             ;Loop back
  2818.  
  2819. p1_proc:    lodsb                   ;Get char
  2820.             test al,al              ;Check for null
  2821.             jz p1_done
  2822.             cmp al,'%'              ; %% = percent
  2823.             je p1_putc
  2824.             cmp al,'d'              ; %d = integer
  2825.             je p1_int
  2826.             cmp al,'l'              ; %l = long int
  2827.             je p1_long
  2828.             cmp al,'x'              ; %x = hex
  2829.             je p1_hex
  2830.             cmp al,'c'              ; %c = char
  2831.             je p1_char
  2832.             cmp al,'s'              ; %s = string
  2833.             je p1_str
  2834.             jmp p1_loop             ;Invalid, ignore
  2835.  
  2836. p1_done:    popa                    ;Restore registers
  2837.             pop bp                  ;Delete stack frame
  2838.             ret 6                   ;Return
  2839.  
  2840. p1_long:    lodsb                   ;Get char
  2841.             test al,al              ;Check for null
  2842.             jz p1_done
  2843.             cmp al,'d'              ; %ld = long integer
  2844.             je p1_lint
  2845.             cmp al,'x'              ; %lx = long hex
  2846.             je p1_lhex
  2847.             jmp p1_loop             ;Invalid, ignore
  2848.  
  2849. p1_int:     push [word bx]          ;itoa(*bx, PRT_BUF);
  2850.             push offset PRT_BUF
  2851.             call itoa
  2852.             inc bx                  ;Advance pointer
  2853.             inc bx
  2854.             mov di,offset PRT_BUF   ;Print alpha string
  2855.             jmp p1_alpha
  2856.  
  2857. p1_lint:    push [word bx+2]
  2858.             push [word bx]          ;ltoa(*bx, PRT_BUF);
  2859.             push offset PRT_BUF
  2860.             call ltoa
  2861.             add bx,4                ;Advance pointer
  2862.             mov di,offset PRT_BUF   ;Print alpha string
  2863.             jmp p1_alpha
  2864.  
  2865. p1_hex:     mov ax,[bx]             ;AX = arg
  2866.             call p1_chex            ;Convert to hex
  2867.             inc bx                  ;Advance pointer
  2868.             inc bx
  2869.             jmp p1_loop             ;Loop back
  2870.  
  2871. p1_lhex:    mov ax,[bx+2]           ;AX = high word
  2872.             call p1_chex            ;Convert to hex
  2873.             mov ax,[bx]             ;AX = low word
  2874.             call p1_chex            ;Convert to hex
  2875.             add bx,4                ;Advance pointer
  2876.             jmp p1_loop             ;Loop back
  2877.  
  2878. p1_char:    mov al,[bx]             ;Output char
  2879.             push ax
  2880.             call dx
  2881.             inc bx                  ;Advance pointer
  2882.             jmp p1_loop             ;Loop back
  2883.  
  2884. p1_str:     mov al,[bx]             ;Get char
  2885.             inc bx                  ;Advance pointer
  2886.             test al,al              ;Check for null
  2887.             jz p1_sdone
  2888.             push ax                 ;Output char
  2889.             call dx
  2890.             jmp p1_str              ;Loop back
  2891.  
  2892. p1_sdone:   jmp p1_loop             ;Return to main loop
  2893.  
  2894. p1_alpha:   mov al,[di]             ;Get char
  2895.             test al,al              ;Check for null
  2896.             jz p1_sdone
  2897.             push ax                 ;Output char
  2898.             call dx
  2899.             inc di                  ;Advance pointer
  2900.             jmp p1_alpha            ;Loop back
  2901.  
  2902. p1_chex:    mov cx,4                ;4 hex digits
  2903.             xchg al,ah              ;Reverse the order
  2904.             ror ah,cl               ;of the hex digits
  2905.             ror al,cl               ;in AX
  2906.  
  2907. p1_hloop:   push ax                 ;Save AX
  2908.             and al,0Fh              ;Keep 4 bits
  2909.             cmp al,0Ah              ;Compute the hex digit,
  2910.             sbb al,69h              ;using Improved Allison's Algorithm
  2911.             das
  2912.             push ax                 ;Output char
  2913.             call dx
  2914.             pop ax                  ;Restore AX
  2915.             shr ax,4                ;Shift it over
  2916.             loop p1_hloop           ;Loop back
  2917.             ret                     ;Return
  2918.  
  2919. EndP        xprintf
  2920.  
  2921. End
  2922.  
  2923. ~~~C_CPULVL
  2924. Ideal
  2925.  
  2926. Public      cputype
  2927.  
  2928. Model Tiny
  2929. P186
  2930. CodeSeg
  2931.  
  2932. ;**************************** cputype() -- Returns CPU level
  2933. ;int cputype(void);
  2934.  
  2935. Proc        cputype
  2936.  
  2937.             push es            ;Save ES
  2938.             pusha              ;Save gen. regs
  2939.  
  2940.             call p1_getcpu     ;Call main procedure
  2941.  
  2942.             shr ax,8           ;AL = AH, AH = 0
  2943.             mov es,ax          ;ES = AX
  2944.             popa               ;Restore gen. regs
  2945.             mov ax,es          ;Return value in AX
  2946.             pop es             ;Restore ES
  2947.             ret                ;Return
  2948.  
  2949. p1_getcpu:  mov cx,0121h       ;If CH can be shifted by 21h,
  2950.             shl ch,cl          ;then it's an 8086, because
  2951.             jz p1_8086         ;a 186+ limits shift counts.
  2952.  
  2953.             push sp            ;If SP is pushed as its
  2954.             pop ax             ;original value, then
  2955.             cmp ax,sp          ;it's a 286+.
  2956.             jne p1_186
  2957.  
  2958.             pushf              ;Save flags
  2959.             cli                ;No interrupts
  2960.             pushf              ;AX = flags
  2961.             pop ax
  2962.             xor ax,7000h       ;Toggle IOPL bit
  2963.             push ax            ;Flags = AX
  2964.             popf
  2965.             pushf              ;BX = flags
  2966.             pop bx
  2967.             popf               ;Restore flags
  2968.             cmp ax,bx          ;If the bit was not
  2969.             jne p1_286         ;reset, it's a 386+
  2970. P386
  2971.             push bp            ;Align stack to dword
  2972.             mov bp,sp
  2973.             and sp,0FFFCh
  2974.             pushfd             ;Save eflags
  2975.             cli                ;No interrupts
  2976.             pushfd             ;EAX = eflags
  2977.             pop eax
  2978.             mov ebx,eax        ;EBX = eflags
  2979.             xor eax,40000h     ;Toggle AC bit
  2980.             push eax           ;Eflags = EAX
  2981.             popfd
  2982.             pushfd             ;EAX = eflags
  2983.             pop eax
  2984.             popfd              ;Restore eflags
  2985.             mov sp,bp          ;Restore stack
  2986.             pop bp
  2987.             cmp eax,ebx        ;If the bit was not
  2988.             je p1_386          ;reset, it's a 486+
  2989.  
  2990.             pushfd             ;Save eflags
  2991.             cli                ;No interrupts
  2992.             pushfd             ;EAX = eflags
  2993.             pop eax
  2994.             xor eax,200000h    ;Toggle ID bit
  2995.             push eax           ;Eflags = EAX
  2996.             popfd
  2997.             pushfd             ;EBX = eflags
  2998.             pop ebx
  2999.             popfd              ;Restore eflags
  3000.             cmp eax,ebx        ;If the bit was not
  3001.             jne p1_486         ;reset, it's a 586+
  3002. P586
  3003.             xor eax,eax        ;EAX = 1
  3004.             inc ax
  3005.             cpuid              ;Get CPU type
  3006.             ret                ;Return
  3007. P186
  3008. p1_486:     mov ah,4           ;486, return 4
  3009.             ret
  3010.  
  3011. p1_386:     mov ah,3           ;386, return 3
  3012.             ret
  3013.  
  3014. p1_286:     mov ah,2           ;286, return 2
  3015.             ret
  3016.  
  3017. p1_186:     mov ah,1           ;186, return 1
  3018.             ret
  3019.  
  3020. p1_8086:    mov ah,0           ;8086, return 0
  3021.             ret
  3022.  
  3023. EndP        cputype
  3024.  
  3025. End
  3026.  
  3027. ~~~C_FPULVL
  3028. Ideal
  3029.  
  3030. Public      fputype
  3031.  
  3032. Model Tiny
  3033. P186
  3034. CodeSeg
  3035.  
  3036. ;**************************** fputype() -- Returns FPU level, init FPU
  3037. ;int fputype(void);                        -1 means no FPU
  3038.  
  3039. Proc        fputype
  3040.  
  3041.             push es            ;Save ES
  3042.             pusha              ;Save gen. regs
  3043.  
  3044.             call p2_getfpu     ;Get FPU type
  3045.  
  3046.             mov es,ax          ;ES = AX
  3047.             popa               ;Restore gen. regs
  3048.             mov ax,es          ;Return value in AX
  3049.             pop es             ;Restore ES
  3050.             ret                ;Return
  3051. P8087
  3052. p2_getfpu:  fninit             ;Initialize FPU
  3053.             mov [Junk],55AAh   ;Set junk value
  3054.             fnstsw [Junk]      ;Store status word
  3055.             cmp [byte Junk],0  ;If it's not 0, no FPU
  3056.             jne p2_nofpu
  3057.             fnstcw [Junk]      ;Store control word
  3058.             mov ax,[Junk]      ;If the bits are not the way
  3059.             and ax,103Fh       ;they should be, no FPU
  3060.             cmp ax,3Fh
  3061.             jne p2_nofpu
  3062.  
  3063.             and [Junk],0FF7Fh  ;Clear interrupt bit
  3064.             fldcw [Junk]       ;Load control word
  3065.             fdisi              ;Disable interrupts
  3066.             fstcw [Junk]       ;Store control word
  3067.             test [Junk],80h    ;If it changed, it's an 8087
  3068.             jnz p2_8087
  3069. P286
  3070. P287
  3071.             finit              ;Re-initialize
  3072.             fld1               ;Divide 1 by 0 to get
  3073.             fldz               ;a positive infinity
  3074.             fdiv
  3075.             fld st             ;Get a negative infinity
  3076.             fchs
  3077.             fcompp             ;Compare them
  3078.             fstsw ax           ;Store status word
  3079.             sahf               ;If the FPU thought that they
  3080.             je p2_287          ;were equal, it's a 287
  3081.  
  3082.             mov ax,3           ;387, return 3
  3083.             finit              ;Init processor
  3084.             ret
  3085.  
  3086. p2_287:     mov ax,2           ;287, return 2
  3087.             finit              ;Init processor
  3088.             ret
  3089. P186
  3090. P8087
  3091. p2_8087:    xor ax,ax          ;8087, return 0
  3092.             finit              ;Init processor
  3093.             ret
  3094.  
  3095. p2_nofpu:   mov ax,-1          ;No FPU, return -1
  3096.             ret
  3097.  
  3098. Junk        dw 0
  3099.  
  3100. EndP        fputype
  3101.  
  3102. End
  3103.  
  3104. ~~~C_RAND
  3105. Ideal
  3106.  
  3107. Public      rand,srand,truerand
  3108.  
  3109. Model Tiny
  3110. P186
  3111. CodeSeg
  3112.  
  3113. RandNum     dw 0,0                  ;Random number
  3114.  
  3115. ;****************** rand() -- Returns a random number below N
  3116. ;int rand(int max);
  3117.  
  3118. max         equ bp+4
  3119.  
  3120. Proc        rand
  3121.  
  3122.             push bp                 ;Set up stack frame
  3123.             mov bp,sp
  3124.             push bx cx dx           ;Save registers
  3125.  
  3126.             mov ax,[RandNum]        ;CX:BX = RandNum * 0019660Dh + 10DCDh
  3127.             mov dx,660Dh            ;low * low
  3128.             mul dx
  3129.             mov cx,dx               ;put it in CX:BX
  3130.             mov bx,ax
  3131.             imul ax,[RandNum],0019h ;low * high, high * low
  3132.             imul dx,[RandNum+2],660Dh
  3133.             add cx,ax               ;add them in
  3134.             add cx,dx
  3135.             add bx,0DCDh            ;add in the 10DCDh
  3136.             adc cx,0001h
  3137.  
  3138.             mov [RandNum],bx        ;Save random number
  3139.             mov [RandNum+2],cx
  3140.  
  3141.             xchg ax,cx              ;AX = low 15 bits of CX
  3142.             shl ax,1                ; plus high bit of BX
  3143.             rol bx,1
  3144.             and bx,1
  3145.             or ax,bx
  3146.             mov bx,[max]            ;BX = maximum
  3147.             xor dx,dx               ;Zero DX
  3148.             test bx,bx              ;Can't divide by zero
  3149.             jz p1_skip
  3150.             div bx                  ;Divide by BX
  3151. p1_skip:    xchg ax,dx              ;Result in AX
  3152.  
  3153.             pop dx cx bx            ;Restore registers
  3154.             pop bp                  ;Delete stack frame
  3155.             ret 2                   ;Return
  3156.  
  3157. EndP        rand
  3158.  
  3159. ;****************** srand() -- Seeds the RNG with the time
  3160. ;void srand(void);
  3161.  
  3162. Proc        srand
  3163.  
  3164.             push bp                 ;Set up stack frame
  3165.             mov bp,sp
  3166.             push ax es              ;Save registers
  3167.  
  3168.             push 40h                ;ES = BIOS segment
  3169.             pop es
  3170.  
  3171.             mov ax,[es:6Ch]         ;Get low word
  3172.             mov [RandNum],ax        ;Save it
  3173.             mov ax,[es:6Eh]         ;Get high word
  3174.             mov [RandNum+2],ax      ;Save it
  3175.  
  3176.             pop es ax               ;Restore registers
  3177.             pop bp                  ;Delete stack frame
  3178.             ret                     ;Return
  3179.  
  3180. EndP        srand
  3181.  
  3182. ;****************** truerand() -- Returns a true random number below N
  3183. ;int truerand(int max);           Extremely slow, but it works
  3184.  
  3185. max         equ bp+4
  3186.  
  3187. Proc        truerand
  3188.  
  3189.             push bp                 ;Set up stack frame
  3190.             mov bp,sp
  3191.             push bx cx dx           ;Save registers
  3192.  
  3193.             mov cx,96               ;96 iterations
  3194.             cli                     ;No interrupts allowed
  3195.  
  3196. p1_loop:    mov al,06h              ;Set timer command
  3197.             out 43h,al
  3198.             jmp $+2
  3199.             in al,40h               ;Read LSB of timer
  3200.             xor dl,al               ;XOR into DX
  3201.             jmp $+2
  3202.             in al,40h               ;Read MSB of timer
  3203.             xor dl,al               ;XOR into DX
  3204.             rol dx,3                ;Rotate left
  3205.             loop p1_loop            ;Loop back
  3206.  
  3207.             sti                     ;Enable interrupts
  3208.             xchg ax,dx              ;Result in AX
  3209.  
  3210.             mov bx,[max]            ;BX = maximum
  3211.             xor dx,dx               ;Zero DX
  3212.             test bx,bx              ;Can't divide by zero
  3213.             jz p3_skip
  3214.             div bx                  ;Divide by BX
  3215. p3_skip:    xchg ax,dx              ;Result in AX
  3216.  
  3217.             pop dx cx bx            ;Restore registers
  3218.             pop bp                  ;Delete stack frame
  3219.             ret 2                   ;Return
  3220.  
  3221. EndP        truerand
  3222.  
  3223. End
  3224.  
  3225. ~~~C_DELAY
  3226. Ideal
  3227.  
  3228. Public      delay
  3229.  
  3230. Model Tiny
  3231. P186
  3232. CodeSeg
  3233.  
  3234. ;****************** delay() -- Delay in milliseconds
  3235. ;void delay(int dtime);
  3236.  
  3237. dtime       equ bp+4
  3238.  
  3239. Proc        delay
  3240.  
  3241.             push bp                 ;Set up stack frame
  3242.             mov bp,sp
  3243.             pusha                   ;Save registers
  3244.  
  3245.             mov ax,[dtime]          ;AX = time in milliseconds
  3246.             mov dx,1000             ;Multiply by 1000
  3247.             mul dx                  ;DX:AX = time in microseconds
  3248.  
  3249.             xchg ax,dx              ;CX:DX = time
  3250.             xchg ax,cx
  3251.             mov ah,86h              ;BIOS Delay Service
  3252.             int 15h
  3253.  
  3254.             popa                    ;Restore registers
  3255.             pop bp                  ;Delete stack frame
  3256.             ret 2                   ;Return
  3257.  
  3258. EndP        delay
  3259.  
  3260. End
  3261.  
  3262. ~~~C_SOUND
  3263. Ideal
  3264.  
  3265. Public      sound,nosound
  3266.  
  3267. Model Tiny
  3268. P186
  3269. CodeSeg
  3270.  
  3271. ;****************** sound() -- Turn on speaker at specific frequency
  3272. ;void sound(int freq);
  3273.  
  3274. freq        equ bp+4
  3275.  
  3276. Proc        sound
  3277.  
  3278.             push bp                 ;Set up stack frame
  3279.             mov bp,sp
  3280.             pusha                   ;Save registers
  3281.  
  3282.             mov dx,12h              ;BX = 1193180 / freq.
  3283.             mov ax,34DCh
  3284.             mov bx,[freq]
  3285.             div bx
  3286.             xchg bx,ax
  3287.  
  3288.             mov al,0B6h             ;Set frequency
  3289.             out 43h,al
  3290.             mov al,bl
  3291.             out 42h,al
  3292.             mov al,bh
  3293.             out 42h,al
  3294.  
  3295.             in al,61h               ;Turn on speaker
  3296.             or al,3
  3297.             out 61h,al
  3298.  
  3299.             popa                    ;Restore registers
  3300.             pop bp                  ;Delete stack frame
  3301.             ret 2                   ;Return
  3302.  
  3303. EndP        sound
  3304.  
  3305. ;****************** nosound() -- Turn off speaker
  3306. ;void nosound(void);
  3307.  
  3308. Proc        nosound
  3309.  
  3310.             push ax                 ;Save AX
  3311.  
  3312.             in al,61h               ;Turn off speaker
  3313.             and al,0FCh
  3314.             out 61h,al
  3315.  
  3316.             pop ax                  ;Restore AX
  3317.             ret                     ;Return
  3318.  
  3319. EndP        nosound
  3320.  
  3321. End
  3322.